@integrity-labs/agt-cli 0.28.744 → 0.28.745
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.
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
safeWriteJsonAtomic,
|
|
58
58
|
setConfigHash,
|
|
59
59
|
tripClass
|
|
60
|
-
} from "../chunk-
|
|
60
|
+
} from "../chunk-7ENZBKCO.js";
|
|
61
61
|
import {
|
|
62
62
|
getProjectDir as getProjectDir2,
|
|
63
63
|
getReadyTasks,
|
|
@@ -209,8 +209,8 @@ import {
|
|
|
209
209
|
} from "../chunk-XWVM4KPK.js";
|
|
210
210
|
|
|
211
211
|
// src/lib/manager-worker.ts
|
|
212
|
-
import { createHash as
|
|
213
|
-
import { readFileSync as
|
|
212
|
+
import { createHash as createHash20 } from "crypto";
|
|
213
|
+
import { readFileSync as readFileSync32, writeFileSync as writeFileSync18, mkdirSync as mkdirSync14, existsSync as existsSync19, rmSync as rmSync8, readdirSync as readdirSync12, statSync as statSync11, unlinkSync as unlinkSync6, renameSync as renameSync11, utimesSync as utimesSync4 } from "fs";
|
|
214
214
|
|
|
215
215
|
// src/lib/atomic-file-replace.ts
|
|
216
216
|
import { copyFileSync, renameSync, unlinkSync } from "fs";
|
|
@@ -236,7 +236,7 @@ function defaultUnique() {
|
|
|
236
236
|
|
|
237
237
|
// src/lib/manager-worker.ts
|
|
238
238
|
import { execFileSync as syncExecFile } from "child_process";
|
|
239
|
-
import { join as
|
|
239
|
+
import { join as join41, dirname as dirname10, delimiter as pathDelimiter } from "path";
|
|
240
240
|
import { homedir as homedir17 } from "os";
|
|
241
241
|
import { fileURLToPath } from "url";
|
|
242
242
|
|
|
@@ -1769,12 +1769,12 @@ function isPathInsideDir(candidate, dir) {
|
|
|
1769
1769
|
return resolvedCandidate.startsWith(resolvedDir.endsWith(sep) ? resolvedDir : resolvedDir + sep);
|
|
1770
1770
|
}
|
|
1771
1771
|
function findMissingMcpBundles(mcpConfigPath, deps = {}) {
|
|
1772
|
-
const
|
|
1773
|
-
const
|
|
1772
|
+
const existsSync20 = deps.existsSync ?? nodeExistsSync;
|
|
1773
|
+
const readFileSync33 = deps.readFileSync ?? nodeReadFileSync;
|
|
1774
1774
|
const mcpDir = deps.mcpDir ?? getSharedMcpDir();
|
|
1775
1775
|
let parsed;
|
|
1776
1776
|
try {
|
|
1777
|
-
parsed = JSON.parse(
|
|
1777
|
+
parsed = JSON.parse(readFileSync33(mcpConfigPath, "utf-8"));
|
|
1778
1778
|
} catch {
|
|
1779
1779
|
return [];
|
|
1780
1780
|
}
|
|
@@ -1794,7 +1794,7 @@ function findMissingMcpBundles(mcpConfigPath, deps = {}) {
|
|
|
1794
1794
|
if (seenPaths.has(resolvedBundlePath)) continue;
|
|
1795
1795
|
let present;
|
|
1796
1796
|
try {
|
|
1797
|
-
present =
|
|
1797
|
+
present = existsSync20(bundlePath);
|
|
1798
1798
|
} catch {
|
|
1799
1799
|
continue;
|
|
1800
1800
|
}
|
|
@@ -5405,7 +5405,7 @@ async function resolveKnowledgeFromManifest(args) {
|
|
|
5405
5405
|
}));
|
|
5406
5406
|
}
|
|
5407
5407
|
|
|
5408
|
-
// src/lib/
|
|
5408
|
+
// src/lib/memory-cache.ts
|
|
5409
5409
|
import { createHash as createHash10 } from "crypto";
|
|
5410
5410
|
import {
|
|
5411
5411
|
existsSync as existsSync7,
|
|
@@ -5419,17 +5419,17 @@ import {
|
|
|
5419
5419
|
writeFileSync as writeFileSync9
|
|
5420
5420
|
} from "fs";
|
|
5421
5421
|
import { join as join24 } from "path";
|
|
5422
|
-
var
|
|
5422
|
+
var MEMORY_FETCH_CHUNK = 100;
|
|
5423
5423
|
var CACHE_TTL_MS2 = 30 * 24 * 60 * 60 * 1e3;
|
|
5424
5424
|
var SWEEP_INTERVAL_MS2 = 24 * 60 * 60 * 1e3;
|
|
5425
|
-
var lastSweepAt2 =
|
|
5426
|
-
function
|
|
5425
|
+
var lastSweepAt2 = /* @__PURE__ */ new Map();
|
|
5426
|
+
function memoryHash(content) {
|
|
5427
5427
|
return createHash10("sha256").update(content, "utf8").digest("hex");
|
|
5428
5428
|
}
|
|
5429
5429
|
function cachePath2(cacheDir, hash) {
|
|
5430
5430
|
return join24(cacheDir, hash);
|
|
5431
5431
|
}
|
|
5432
|
-
function
|
|
5432
|
+
function readCachedMemory(cacheDir, hash) {
|
|
5433
5433
|
const path = cachePath2(cacheDir, hash);
|
|
5434
5434
|
try {
|
|
5435
5435
|
const content = readFileSync18(path, "utf-8");
|
|
@@ -5443,21 +5443,21 @@ function readCachedSkill(cacheDir, hash) {
|
|
|
5443
5443
|
return null;
|
|
5444
5444
|
}
|
|
5445
5445
|
}
|
|
5446
|
-
function
|
|
5447
|
-
if (
|
|
5446
|
+
function writeCachedMemory(cacheDir, hash, content) {
|
|
5447
|
+
if (memoryHash(content) !== hash) return false;
|
|
5448
5448
|
try {
|
|
5449
5449
|
mkdirSync7(cacheDir, { recursive: true });
|
|
5450
5450
|
const tmp = `${cachePath2(cacheDir, hash)}.tmp-${process.pid}`;
|
|
5451
5451
|
writeFileSync9(tmp, content, "utf-8");
|
|
5452
5452
|
renameSync6(tmp, cachePath2(cacheDir, hash));
|
|
5453
|
-
return
|
|
5453
|
+
return true;
|
|
5454
5454
|
} catch {
|
|
5455
|
-
return
|
|
5455
|
+
return false;
|
|
5456
5456
|
}
|
|
5457
5457
|
}
|
|
5458
|
-
function
|
|
5459
|
-
if (now - lastSweepAt2 < SWEEP_INTERVAL_MS2) return;
|
|
5460
|
-
lastSweepAt2
|
|
5458
|
+
function sweepMemoryCache(cacheDir, now = Date.now()) {
|
|
5459
|
+
if (now - (lastSweepAt2.get(cacheDir) ?? 0) < SWEEP_INTERVAL_MS2) return;
|
|
5460
|
+
lastSweepAt2.set(cacheDir, now);
|
|
5461
5461
|
try {
|
|
5462
5462
|
if (!existsSync7(cacheDir)) return;
|
|
5463
5463
|
for (const name of readdirSync6(cacheDir)) {
|
|
@@ -5470,6 +5470,115 @@ function sweepSkillCache(cacheDir, now = Date.now()) {
|
|
|
5470
5470
|
} catch {
|
|
5471
5471
|
}
|
|
5472
5472
|
}
|
|
5473
|
+
async function resolveMemoriesFromManifest(args) {
|
|
5474
|
+
const { manifest, cacheDir, fetchContents, log: log2 } = args;
|
|
5475
|
+
const bodies = /* @__PURE__ */ new Map();
|
|
5476
|
+
const missing = [];
|
|
5477
|
+
const missingSeen = /* @__PURE__ */ new Set();
|
|
5478
|
+
for (const entry of manifest) {
|
|
5479
|
+
if (!entry.hash || bodies.has(entry.hash)) continue;
|
|
5480
|
+
const cached = readCachedMemory(cacheDir, entry.hash);
|
|
5481
|
+
if (cached !== null) bodies.set(entry.hash, cached);
|
|
5482
|
+
else if (!missingSeen.has(entry.hash)) {
|
|
5483
|
+
missingSeen.add(entry.hash);
|
|
5484
|
+
missing.push(entry.hash);
|
|
5485
|
+
}
|
|
5486
|
+
}
|
|
5487
|
+
if (missing.length > 0) {
|
|
5488
|
+
for (let i = 0; i < missing.length; i += MEMORY_FETCH_CHUNK) {
|
|
5489
|
+
const chunk2 = missing.slice(i, i + MEMORY_FETCH_CHUNK);
|
|
5490
|
+
try {
|
|
5491
|
+
for (const { hash, content } of await fetchContents(chunk2)) {
|
|
5492
|
+
if (!writeCachedMemory(cacheDir, hash, content)) {
|
|
5493
|
+
log2?.(`[memory-cache] hash mismatch for ${hash} \u2014 dropping this poll`);
|
|
5494
|
+
continue;
|
|
5495
|
+
}
|
|
5496
|
+
bodies.set(hash, content);
|
|
5497
|
+
}
|
|
5498
|
+
} catch (err) {
|
|
5499
|
+
log2?.(`[memory-cache] fetch failed for ${chunk2.length} entries: ${err.message}`);
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5502
|
+
}
|
|
5503
|
+
sweepMemoryCache(cacheDir);
|
|
5504
|
+
const memories = [];
|
|
5505
|
+
let unresolved = 0;
|
|
5506
|
+
for (const entry of manifest) {
|
|
5507
|
+
const content = entry.hash ? bodies.get(entry.hash) : void 0;
|
|
5508
|
+
if (content === void 0) {
|
|
5509
|
+
unresolved++;
|
|
5510
|
+
continue;
|
|
5511
|
+
}
|
|
5512
|
+
memories.push({ name: entry.name, type: entry.type, content });
|
|
5513
|
+
}
|
|
5514
|
+
return { memories, unresolved };
|
|
5515
|
+
}
|
|
5516
|
+
|
|
5517
|
+
// src/lib/skill-cache.ts
|
|
5518
|
+
import { createHash as createHash11 } from "crypto";
|
|
5519
|
+
import {
|
|
5520
|
+
existsSync as existsSync8,
|
|
5521
|
+
mkdirSync as mkdirSync8,
|
|
5522
|
+
readFileSync as readFileSync19,
|
|
5523
|
+
readdirSync as readdirSync7,
|
|
5524
|
+
renameSync as renameSync7,
|
|
5525
|
+
rmSync as rmSync5,
|
|
5526
|
+
statSync as statSync7,
|
|
5527
|
+
utimesSync as utimesSync3,
|
|
5528
|
+
writeFileSync as writeFileSync10
|
|
5529
|
+
} from "fs";
|
|
5530
|
+
import { join as join25 } from "path";
|
|
5531
|
+
var SKILL_FETCH_CHUNK = 100;
|
|
5532
|
+
var CACHE_TTL_MS3 = 30 * 24 * 60 * 60 * 1e3;
|
|
5533
|
+
var SWEEP_INTERVAL_MS3 = 24 * 60 * 60 * 1e3;
|
|
5534
|
+
var lastSweepAt3 = 0;
|
|
5535
|
+
function skillHash(content) {
|
|
5536
|
+
return createHash11("sha256").update(content, "utf8").digest("hex");
|
|
5537
|
+
}
|
|
5538
|
+
function cachePath3(cacheDir, hash) {
|
|
5539
|
+
return join25(cacheDir, hash);
|
|
5540
|
+
}
|
|
5541
|
+
function readCachedSkill(cacheDir, hash) {
|
|
5542
|
+
const path = cachePath3(cacheDir, hash);
|
|
5543
|
+
try {
|
|
5544
|
+
const content = readFileSync19(path, "utf-8");
|
|
5545
|
+
try {
|
|
5546
|
+
const now = /* @__PURE__ */ new Date();
|
|
5547
|
+
utimesSync3(path, now, now);
|
|
5548
|
+
} catch {
|
|
5549
|
+
}
|
|
5550
|
+
return content;
|
|
5551
|
+
} catch {
|
|
5552
|
+
return null;
|
|
5553
|
+
}
|
|
5554
|
+
}
|
|
5555
|
+
function writeCachedSkill(cacheDir, hash, content) {
|
|
5556
|
+
if (skillHash(content) !== hash) return "mismatch";
|
|
5557
|
+
try {
|
|
5558
|
+
mkdirSync8(cacheDir, { recursive: true });
|
|
5559
|
+
const tmp = `${cachePath3(cacheDir, hash)}.tmp-${process.pid}`;
|
|
5560
|
+
writeFileSync10(tmp, content, "utf-8");
|
|
5561
|
+
renameSync7(tmp, cachePath3(cacheDir, hash));
|
|
5562
|
+
return "written";
|
|
5563
|
+
} catch {
|
|
5564
|
+
return "write-failed";
|
|
5565
|
+
}
|
|
5566
|
+
}
|
|
5567
|
+
function sweepSkillCache(cacheDir, now = Date.now()) {
|
|
5568
|
+
if (now - lastSweepAt3 < SWEEP_INTERVAL_MS3) return;
|
|
5569
|
+
lastSweepAt3 = now;
|
|
5570
|
+
try {
|
|
5571
|
+
if (!existsSync8(cacheDir)) return;
|
|
5572
|
+
for (const name of readdirSync7(cacheDir)) {
|
|
5573
|
+
const path = join25(cacheDir, name);
|
|
5574
|
+
try {
|
|
5575
|
+
if (now - statSync7(path).mtimeMs > CACHE_TTL_MS3) rmSync5(path, { force: true });
|
|
5576
|
+
} catch {
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5579
|
+
} catch {
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5473
5582
|
async function collectBodies(hashes, cacheDir, fetchContents, lane, log2) {
|
|
5474
5583
|
const bodies = /* @__PURE__ */ new Map();
|
|
5475
5584
|
const missing = [];
|
|
@@ -5748,18 +5857,18 @@ function resolveConditionalResponse(wire, hasCachedBody) {
|
|
|
5748
5857
|
}
|
|
5749
5858
|
|
|
5750
5859
|
// src/lib/channel-hash-cache.ts
|
|
5751
|
-
import { existsSync as
|
|
5752
|
-
import { join as
|
|
5860
|
+
import { existsSync as existsSync9, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "fs";
|
|
5861
|
+
import { join as join26 } from "path";
|
|
5753
5862
|
var CACHE_FILENAME = "channel-hash-cache.json";
|
|
5754
5863
|
function getChannelHashCacheFile(configDir) {
|
|
5755
|
-
return
|
|
5864
|
+
return join26(configDir, CACHE_FILENAME);
|
|
5756
5865
|
}
|
|
5757
5866
|
function loadChannelHashCache(target, configDir) {
|
|
5758
5867
|
const path = getChannelHashCacheFile(configDir);
|
|
5759
|
-
if (!
|
|
5868
|
+
if (!existsSync9(path)) return;
|
|
5760
5869
|
let parsed;
|
|
5761
5870
|
try {
|
|
5762
|
-
parsed = JSON.parse(
|
|
5871
|
+
parsed = JSON.parse(readFileSync20(path, "utf-8"));
|
|
5763
5872
|
} catch {
|
|
5764
5873
|
return;
|
|
5765
5874
|
}
|
|
@@ -5773,14 +5882,14 @@ function saveChannelHashCache(source, configDir) {
|
|
|
5773
5882
|
const obj = {};
|
|
5774
5883
|
for (const [key, value] of source) obj[key] = value;
|
|
5775
5884
|
try {
|
|
5776
|
-
|
|
5885
|
+
writeFileSync11(path, JSON.stringify(obj, null, 2));
|
|
5777
5886
|
} catch {
|
|
5778
5887
|
}
|
|
5779
5888
|
}
|
|
5780
5889
|
|
|
5781
5890
|
// src/lib/sender-policy-baseline.ts
|
|
5782
|
-
import { existsSync as
|
|
5783
|
-
import { join as
|
|
5891
|
+
import { existsSync as existsSync10, readFileSync as readFileSync21 } from "fs";
|
|
5892
|
+
import { join as join27 } from "path";
|
|
5784
5893
|
var BASELINE_FILENAME = "sender-policy-baseline.json";
|
|
5785
5894
|
var SENDER_POLICY_BASELINE_VERSION = 1;
|
|
5786
5895
|
var BASELINE_CONCERNS = ["senderPolicy", "slackBehaviour", "msteamsBehaviour"];
|
|
@@ -5792,14 +5901,14 @@ function createDeliveryBaselineMaps() {
|
|
|
5792
5901
|
};
|
|
5793
5902
|
}
|
|
5794
5903
|
function getSenderPolicyBaselineFile(configDir) {
|
|
5795
|
-
return
|
|
5904
|
+
return join27(configDir, BASELINE_FILENAME);
|
|
5796
5905
|
}
|
|
5797
5906
|
function loadSenderPolicyBaseline(target, configDir, log2) {
|
|
5798
5907
|
const path = getSenderPolicyBaselineFile(configDir);
|
|
5799
|
-
if (!
|
|
5908
|
+
if (!existsSync10(path)) return;
|
|
5800
5909
|
let parsed;
|
|
5801
5910
|
try {
|
|
5802
|
-
parsed = JSON.parse(
|
|
5911
|
+
parsed = JSON.parse(readFileSync21(path, "utf-8"));
|
|
5803
5912
|
} catch (err) {
|
|
5804
5913
|
log2?.(
|
|
5805
5914
|
`[sender-policy] discarding corrupt ${BASELINE_FILENAME} (${err.message}) - restrictive-policy agents will take one fail-closed restart`
|
|
@@ -5848,8 +5957,8 @@ function saveSenderPolicyBaseline(source, configDir, log2) {
|
|
|
5848
5957
|
}
|
|
5849
5958
|
|
|
5850
5959
|
// src/lib/stuck-streak-store.ts
|
|
5851
|
-
import { existsSync as
|
|
5852
|
-
import { join as
|
|
5960
|
+
import { existsSync as existsSync11, readFileSync as readFileSync22 } from "fs";
|
|
5961
|
+
import { join as join28 } from "path";
|
|
5853
5962
|
var STORE_FILENAME = "stuck-streaks.json";
|
|
5854
5963
|
var STUCK_STREAK_STORE_VERSION = 1;
|
|
5855
5964
|
var STUCK_STREAK_CONCERNS = ["channelSync", "realtimeRebind"];
|
|
@@ -5857,7 +5966,7 @@ function createStuckStreakMaps() {
|
|
|
5857
5966
|
return { channelSync: /* @__PURE__ */ new Map(), realtimeRebind: /* @__PURE__ */ new Map() };
|
|
5858
5967
|
}
|
|
5859
5968
|
function getStuckStreakStoreFile(configDir) {
|
|
5860
|
-
return
|
|
5969
|
+
return join28(configDir, STORE_FILENAME);
|
|
5861
5970
|
}
|
|
5862
5971
|
function isValidPersistedStreak(value) {
|
|
5863
5972
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
@@ -5896,10 +6005,10 @@ function buildStuckStreakPayload(source) {
|
|
|
5896
6005
|
}
|
|
5897
6006
|
function loadStuckStreaks(target, configDir, log2) {
|
|
5898
6007
|
const path = getStuckStreakStoreFile(configDir);
|
|
5899
|
-
if (!
|
|
6008
|
+
if (!existsSync11(path)) return;
|
|
5900
6009
|
let parsed;
|
|
5901
6010
|
try {
|
|
5902
|
-
parsed = JSON.parse(
|
|
6011
|
+
parsed = JSON.parse(readFileSync22(path, "utf-8"));
|
|
5903
6012
|
} catch (err) {
|
|
5904
6013
|
log2?.(
|
|
5905
6014
|
`[stuck-streaks] discarding corrupt ${STORE_FILENAME} (${err.message}) \u2014 stuck-streak ages restart from zero and one spurious "recovered" close may follow`
|
|
@@ -6416,7 +6525,7 @@ function planGlobalSkillSync(globalSkills, prevIds, hashOf, knownHash, options)
|
|
|
6416
6525
|
}
|
|
6417
6526
|
|
|
6418
6527
|
// src/lib/manager/integration-skill-cache.ts
|
|
6419
|
-
import { join as
|
|
6528
|
+
import { join as join29 } from "path";
|
|
6420
6529
|
function integrationSkillHashKey(agentId, skillId) {
|
|
6421
6530
|
return `plugin-skill:${agentId}:${skillId}`;
|
|
6422
6531
|
}
|
|
@@ -6432,21 +6541,21 @@ function forgetIntegrationSkill(cache2, agentId, skillId) {
|
|
|
6432
6541
|
function removeIntegrationSkillFolder(opts) {
|
|
6433
6542
|
forgetIntegrationSkill(opts.cache, opts.agentId, opts.entry);
|
|
6434
6543
|
for (const dir of opts.dirs) {
|
|
6435
|
-
opts.removeDir(
|
|
6544
|
+
opts.removeDir(join29(dir, opts.entry));
|
|
6436
6545
|
}
|
|
6437
6546
|
}
|
|
6438
6547
|
|
|
6439
6548
|
// src/lib/manager/managed-skill-manifest.ts
|
|
6440
|
-
import { existsSync as
|
|
6441
|
-
import { dirname as dirname7, join as
|
|
6549
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync23, writeFileSync as writeFileSync12 } from "fs";
|
|
6550
|
+
import { dirname as dirname7, join as join30 } from "path";
|
|
6442
6551
|
var MANIFEST_VERSION = 1;
|
|
6443
6552
|
function managedSkillManifestPath(agentRootDir) {
|
|
6444
|
-
return
|
|
6553
|
+
return join30(agentRootDir, "managed-skills.json");
|
|
6445
6554
|
}
|
|
6446
6555
|
function readManagedSkillManifest(path) {
|
|
6447
6556
|
try {
|
|
6448
|
-
if (!
|
|
6449
|
-
const parsed = JSON.parse(
|
|
6557
|
+
if (!existsSync12(path)) return /* @__PURE__ */ new Set();
|
|
6558
|
+
const parsed = JSON.parse(readFileSync23(path, "utf-8"));
|
|
6450
6559
|
const ids = Array.isArray(parsed?.globalSkillIds) ? parsed.globalSkillIds : [];
|
|
6451
6560
|
return new Set(ids.filter((id) => typeof id === "string" && id.length > 0));
|
|
6452
6561
|
} catch {
|
|
@@ -6455,12 +6564,12 @@ function readManagedSkillManifest(path) {
|
|
|
6455
6564
|
}
|
|
6456
6565
|
function writeManagedSkillManifest(path, ids) {
|
|
6457
6566
|
try {
|
|
6458
|
-
|
|
6567
|
+
mkdirSync9(dirname7(path), { recursive: true });
|
|
6459
6568
|
const body = {
|
|
6460
6569
|
version: MANIFEST_VERSION,
|
|
6461
6570
|
globalSkillIds: [...ids].sort()
|
|
6462
6571
|
};
|
|
6463
|
-
|
|
6572
|
+
writeFileSync12(path, JSON.stringify(body, null, 2));
|
|
6464
6573
|
} catch {
|
|
6465
6574
|
}
|
|
6466
6575
|
}
|
|
@@ -6575,8 +6684,8 @@ function resolveModelChain(refreshData) {
|
|
|
6575
6684
|
}
|
|
6576
6685
|
|
|
6577
6686
|
// src/lib/manager/claude-auth.ts
|
|
6578
|
-
import { existsSync as
|
|
6579
|
-
import { join as
|
|
6687
|
+
import { existsSync as existsSync13, rmSync as rmSync6 } from "fs";
|
|
6688
|
+
import { join as join31 } from "path";
|
|
6580
6689
|
import { homedir as homedir13 } from "os";
|
|
6581
6690
|
async function applyClaudeAuthToEnv(childEnv, label) {
|
|
6582
6691
|
const apiKey = getApiKey();
|
|
@@ -6589,12 +6698,12 @@ async function applyClaudeAuthToEnv(childEnv, label) {
|
|
|
6589
6698
|
throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
|
|
6590
6699
|
}
|
|
6591
6700
|
childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
|
|
6592
|
-
const claudeDir =
|
|
6701
|
+
const claudeDir = join31(homedir13(), ".claude");
|
|
6593
6702
|
for (const filename of [".credentials.json", "credentials.json"]) {
|
|
6594
|
-
const p =
|
|
6595
|
-
if (
|
|
6703
|
+
const p = join31(claudeDir, filename);
|
|
6704
|
+
if (existsSync13(p)) {
|
|
6596
6705
|
try {
|
|
6597
|
-
|
|
6706
|
+
rmSync6(p, { force: true });
|
|
6598
6707
|
log(`[${label}] Removed ${p} (api_key mode \u2014 preventing OAuth fallback)`);
|
|
6599
6708
|
} catch {
|
|
6600
6709
|
}
|
|
@@ -6673,8 +6782,8 @@ function heartbeatRuntimeAuthFields(probeVerdict) {
|
|
|
6673
6782
|
}
|
|
6674
6783
|
|
|
6675
6784
|
// src/lib/manager/kanban/parsers.ts
|
|
6676
|
-
import { existsSync as
|
|
6677
|
-
import { join as
|
|
6785
|
+
import { existsSync as existsSync14, readFileSync as readFileSync24 } from "fs";
|
|
6786
|
+
import { join as join32 } from "path";
|
|
6678
6787
|
var STANDUP_TEMPLATES = /* @__PURE__ */ new Set(["daily-standup", "end-of-day-summary"]);
|
|
6679
6788
|
var TASK_UPDATE_TEMPLATES = /* @__PURE__ */ new Set(["hourly-status", "task-update"]);
|
|
6680
6789
|
var PLAN_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan"]);
|
|
@@ -6826,12 +6935,12 @@ function getBuiltInSkillContent(skillId) {
|
|
|
6826
6935
|
if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
|
|
6827
6936
|
try {
|
|
6828
6937
|
const candidates = [
|
|
6829
|
-
|
|
6830
|
-
|
|
6938
|
+
join32(process.cwd(), "skills", skillId, "SKILL.md"),
|
|
6939
|
+
join32(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "..", "..", "skills", skillId, "SKILL.md")
|
|
6831
6940
|
];
|
|
6832
6941
|
for (const candidate of candidates) {
|
|
6833
|
-
if (
|
|
6834
|
-
const content =
|
|
6942
|
+
if (existsSync14(candidate)) {
|
|
6943
|
+
const content = readFileSync24(candidate, "utf-8");
|
|
6835
6944
|
const files = [{ relativePath: "SKILL.md", content }];
|
|
6836
6945
|
builtInSkillCache.set(skillId, files);
|
|
6837
6946
|
return files;
|
|
@@ -6972,19 +7081,19 @@ function formatBoardForPrompt(items, template) {
|
|
|
6972
7081
|
}
|
|
6973
7082
|
|
|
6974
7083
|
// src/lib/manager/kanban/nudge-state-cache.ts
|
|
6975
|
-
import { existsSync as
|
|
6976
|
-
import { join as
|
|
7084
|
+
import { existsSync as existsSync15, readFileSync as readFileSync25, writeFileSync as writeFileSync13 } from "fs";
|
|
7085
|
+
import { join as join33 } from "path";
|
|
6977
7086
|
var CACHE_FILENAME2 = "kanban-nudge-state.json";
|
|
6978
7087
|
var KANBAN_NUDGE_STATE_VERSION = 1;
|
|
6979
7088
|
function getKanbanNudgeStateFile(configDir) {
|
|
6980
|
-
return
|
|
7089
|
+
return join33(configDir, CACHE_FILENAME2);
|
|
6981
7090
|
}
|
|
6982
7091
|
function loadKanbanNudgeState(target, configDir) {
|
|
6983
7092
|
const path = getKanbanNudgeStateFile(configDir);
|
|
6984
|
-
if (!
|
|
7093
|
+
if (!existsSync15(path)) return;
|
|
6985
7094
|
let parsed;
|
|
6986
7095
|
try {
|
|
6987
|
-
parsed = JSON.parse(
|
|
7096
|
+
parsed = JSON.parse(readFileSync25(path, "utf-8"));
|
|
6988
7097
|
} catch {
|
|
6989
7098
|
return;
|
|
6990
7099
|
}
|
|
@@ -7016,13 +7125,13 @@ function saveKanbanNudgeState(source, configDir) {
|
|
|
7016
7125
|
const agents = {};
|
|
7017
7126
|
for (const [codeName, state9] of source) agents[codeName] = state9;
|
|
7018
7127
|
try {
|
|
7019
|
-
|
|
7128
|
+
writeFileSync13(path, JSON.stringify({ version: KANBAN_NUDGE_STATE_VERSION, agents }, null, 2));
|
|
7020
7129
|
} catch {
|
|
7021
7130
|
}
|
|
7022
7131
|
}
|
|
7023
7132
|
|
|
7024
7133
|
// src/lib/manager/kanban/notify.ts
|
|
7025
|
-
import { createHash as
|
|
7134
|
+
import { createHash as createHash12 } from "crypto";
|
|
7026
7135
|
async function enqueueKanbanNotice(opts) {
|
|
7027
7136
|
try {
|
|
7028
7137
|
const res = await api.post(
|
|
@@ -7037,7 +7146,7 @@ async function enqueueKanbanNotice(opts) {
|
|
|
7037
7146
|
return res.ok === true;
|
|
7038
7147
|
} catch (err) {
|
|
7039
7148
|
const errText = err instanceof Error ? err.message : String(err);
|
|
7040
|
-
const errId =
|
|
7149
|
+
const errId = createHash12("sha256").update(errText).digest("hex").slice(0, 12);
|
|
7041
7150
|
log(`[kanban] notice enqueue failed for agent_id=${opts.agentId} error_id=${errId}`);
|
|
7042
7151
|
return false;
|
|
7043
7152
|
}
|
|
@@ -7052,7 +7161,7 @@ async function cancelKanbanNotice(agentId) {
|
|
|
7052
7161
|
return typeof res.cancelled === "number" ? res.cancelled : 0;
|
|
7053
7162
|
} catch (err) {
|
|
7054
7163
|
const errText = err instanceof Error ? err.message : String(err);
|
|
7055
|
-
const errId =
|
|
7164
|
+
const errId = createHash12("sha256").update(errText).digest("hex").slice(0, 12);
|
|
7056
7165
|
log(`[kanban] notice cancel failed for agent_id=${agentId} error_id=${errId}`);
|
|
7057
7166
|
return null;
|
|
7058
7167
|
}
|
|
@@ -7458,7 +7567,7 @@ function deriveScheduledTaskNotify(task) {
|
|
|
7458
7567
|
}
|
|
7459
7568
|
|
|
7460
7569
|
// src/lib/manager/scheduler/runs.ts
|
|
7461
|
-
import { createHash as
|
|
7570
|
+
import { createHash as createHash13 } from "crypto";
|
|
7462
7571
|
async function startRun(opts) {
|
|
7463
7572
|
try {
|
|
7464
7573
|
const res = await api.post(
|
|
@@ -7473,7 +7582,7 @@ async function startRun(opts) {
|
|
|
7473
7582
|
};
|
|
7474
7583
|
} catch (err) {
|
|
7475
7584
|
const errText = err instanceof Error ? err.message : String(err);
|
|
7476
|
-
const errId =
|
|
7585
|
+
const errId = createHash13("sha256").update(errText).digest("hex").slice(0, 12);
|
|
7477
7586
|
log(`[runs] start failed for agent_id=${opts.agent_id} source_type=${opts.source_type} error_id=${errId}`);
|
|
7478
7587
|
return { run_id: null, kanban_item_id: null };
|
|
7479
7588
|
}
|
|
@@ -7512,7 +7621,7 @@ async function finishRun(runId, outcome, options = {}) {
|
|
|
7512
7621
|
return;
|
|
7513
7622
|
} catch (err) {
|
|
7514
7623
|
const errText = err instanceof Error ? err.message : String(err);
|
|
7515
|
-
const errId =
|
|
7624
|
+
const errId = createHash13("sha256").update(errText).digest("hex").slice(0, 12);
|
|
7516
7625
|
const status = err instanceof ApiError ? err.status : 0;
|
|
7517
7626
|
if (isRetryableFinishError(err) && attempt < maxRetries) {
|
|
7518
7627
|
log(
|
|
@@ -7541,7 +7650,7 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
|
|
|
7541
7650
|
return rows.filter((r) => typeof r.output_text === "string" && r.output_text.length > 0).map((r) => ({ startedAt: r.started_at, output: r.output_text }));
|
|
7542
7651
|
} catch (err) {
|
|
7543
7652
|
const errText = err instanceof Error ? err.message : String(err);
|
|
7544
|
-
const errId =
|
|
7653
|
+
const errId = createHash13("sha256").update(errText).digest("hex").slice(0, 12);
|
|
7545
7654
|
log(`[runs] prior-runs lookup failed for task_id=${taskId} error_id=${errId}`);
|
|
7546
7655
|
return [];
|
|
7547
7656
|
}
|
|
@@ -7601,13 +7710,13 @@ function closeSessionRunForCode(codeName, outcome, reason) {
|
|
|
7601
7710
|
}
|
|
7602
7711
|
|
|
7603
7712
|
// src/lib/manager/scheduler/kanban-route.ts
|
|
7604
|
-
import { createHash as
|
|
7605
|
-
import { writeFileSync as
|
|
7713
|
+
import { createHash as createHash15 } from "crypto";
|
|
7714
|
+
import { writeFileSync as writeFileSync14, renameSync as renameSync8, mkdirSync as mkdirSync10, readFileSync as readFileSync26, unlinkSync as unlinkSync3 } from "fs";
|
|
7606
7715
|
import { homedir as homedir14 } from "os";
|
|
7607
|
-
import { join as
|
|
7716
|
+
import { join as join34, dirname as dirname8 } from "path";
|
|
7608
7717
|
|
|
7609
7718
|
// src/lib/manager/scheduler/notify.ts
|
|
7610
|
-
import { createHash as
|
|
7719
|
+
import { createHash as createHash14 } from "crypto";
|
|
7611
7720
|
async function enqueueScheduledTaskNotice(opts) {
|
|
7612
7721
|
try {
|
|
7613
7722
|
const res = await api.post(
|
|
@@ -7624,7 +7733,7 @@ async function enqueueScheduledTaskNotice(opts) {
|
|
|
7624
7733
|
return res.ok === true;
|
|
7625
7734
|
} catch (err) {
|
|
7626
7735
|
const errText = err instanceof Error ? err.message : String(err);
|
|
7627
|
-
const errId =
|
|
7736
|
+
const errId = createHash14("sha256").update(errText).digest("hex").slice(0, 12);
|
|
7628
7737
|
log(
|
|
7629
7738
|
`[scheduled-kanban] notice enqueue failed for agent_id=${opts.agentId} task_id=${opts.taskId} error_id=${errId}`
|
|
7630
7739
|
);
|
|
@@ -7963,19 +8072,19 @@ function resolveScheduledSlackTarget(task) {
|
|
|
7963
8072
|
}
|
|
7964
8073
|
function stampScheduledTurnMarker(codeName, taskId, target) {
|
|
7965
8074
|
try {
|
|
7966
|
-
const file =
|
|
8075
|
+
const file = join34(homedir14(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
|
|
7967
8076
|
const marker = { ts: Date.now(), task_id: taskId, ...target ? { target } : {} };
|
|
7968
8077
|
const tmp = `${file}.tmp`;
|
|
7969
|
-
|
|
7970
|
-
|
|
8078
|
+
writeFileSync14(tmp, JSON.stringify(marker), "utf8");
|
|
8079
|
+
renameSync8(tmp, file);
|
|
7971
8080
|
} catch (err) {
|
|
7972
8081
|
log(`[scheduled-kanban] scheduled-turn marker write failed for '${codeName}': ${err.message}`);
|
|
7973
8082
|
}
|
|
7974
8083
|
}
|
|
7975
8084
|
function clearScheduledTurnMarkerForTask(codeName, taskId) {
|
|
7976
|
-
const file =
|
|
8085
|
+
const file = join34(homedir14(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
|
|
7977
8086
|
try {
|
|
7978
|
-
const raw = JSON.parse(
|
|
8087
|
+
const raw = JSON.parse(readFileSync26(file, "utf8"));
|
|
7979
8088
|
if (typeof raw?.task_id !== "string" || raw.task_id !== taskId) return;
|
|
7980
8089
|
unlinkSync3(file);
|
|
7981
8090
|
log(`[scheduled-kanban] scheduled-turn marker cleared for '${codeName}' (task ${taskId} complete)`);
|
|
@@ -8036,8 +8145,8 @@ async function routeScheduledTaskViaKanban(codeName, agentId, task, prompt, dura
|
|
|
8036
8145
|
}
|
|
8037
8146
|
try {
|
|
8038
8147
|
const doorbell = directChatDoorbellPath(agentId, homedir14());
|
|
8039
|
-
|
|
8040
|
-
|
|
8148
|
+
mkdirSync10(dirname8(doorbell), { recursive: true });
|
|
8149
|
+
writeFileSync14(doorbell, String(Date.now()));
|
|
8041
8150
|
} catch (err) {
|
|
8042
8151
|
log(`[scheduled-kanban] doorbell ring failed for '${codeName}': ${err.message} (notice still queued)`);
|
|
8043
8152
|
}
|
|
@@ -8103,24 +8212,24 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
8103
8212
|
const assertion = parseDeliverAssertion(rawOutput);
|
|
8104
8213
|
if (!assertion.deliver) {
|
|
8105
8214
|
const trimmed = (rawOutput ?? "").trim();
|
|
8106
|
-
const outputHash = trimmed.length === 0 ? "empty" :
|
|
8215
|
+
const outputHash = trimmed.length === 0 ? "empty" : createHash15("sha256").update(trimmed).digest("hex").slice(0, 12);
|
|
8107
8216
|
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}`);
|
|
8108
8217
|
if (delivery?.mode === "announce" && delivery.to) {
|
|
8109
8218
|
await reportDeliveryStatus(agentId, delivery.taskId, { status: "skipped", error_code: "SUPPRESSED_BY_POLICY" });
|
|
8110
8219
|
}
|
|
8111
8220
|
return { ok: true };
|
|
8112
8221
|
}
|
|
8113
|
-
const reasonHash =
|
|
8222
|
+
const reasonHash = createHash15("sha256").update(assertion.reason ?? "").digest("hex").slice(0, 12);
|
|
8114
8223
|
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})`);
|
|
8115
8224
|
rawOutput = assertion.deliverable;
|
|
8116
8225
|
}
|
|
8117
8226
|
const classification = classifyOutput(rawOutput);
|
|
8118
8227
|
if (classification.action === "suppress") {
|
|
8119
8228
|
const trimmed = (rawOutput ?? "").trim();
|
|
8120
|
-
const outputHash = trimmed.length === 0 ? "empty" :
|
|
8229
|
+
const outputHash = trimmed.length === 0 ? "empty" : createHash15("sha256").update(trimmed).digest("hex").slice(0, 12);
|
|
8121
8230
|
log(`[claude-scheduler] Suppressing delivery for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 output_len=${trimmed.length} output_hash=${outputHash}`);
|
|
8122
8231
|
if (classification.suppressedNotes) {
|
|
8123
|
-
const notesHash =
|
|
8232
|
+
const notesHash = createHash15("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
|
|
8124
8233
|
log(`[claude-scheduler] Suppressed notes for '${codeName}' (task=${delivery?.taskId ?? "n/a"}) \u2014 notes_len=${classification.suppressedNotes.length} notes_hash=${notesHash}`);
|
|
8125
8234
|
}
|
|
8126
8235
|
if (delivery?.mode === "announce" && delivery.to) {
|
|
@@ -8186,13 +8295,13 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
8186
8295
|
}
|
|
8187
8296
|
|
|
8188
8297
|
// src/lib/manager/scheduler/execution.ts
|
|
8189
|
-
import { createHash as
|
|
8298
|
+
import { createHash as createHash16 } from "crypto";
|
|
8190
8299
|
import { homedir as homedir15 } from "os";
|
|
8191
|
-
import { join as
|
|
8300
|
+
import { join as join36 } from "path";
|
|
8192
8301
|
|
|
8193
8302
|
// src/lib/agent-serving-probe.ts
|
|
8194
|
-
import { readFileSync as
|
|
8195
|
-
import { join as
|
|
8303
|
+
import { readFileSync as readFileSync27, readdirSync as readdirSync8, statSync as statSync8 } from "fs";
|
|
8304
|
+
import { join as join35 } from "path";
|
|
8196
8305
|
var RATE_LIMIT_WINDOW_MS = 6 * 60 * 60 * 1e3;
|
|
8197
8306
|
function probeRateLimit(args) {
|
|
8198
8307
|
const now = args.now ?? /* @__PURE__ */ new Date();
|
|
@@ -8201,23 +8310,23 @@ function probeRateLimit(args) {
|
|
|
8201
8310
|
const dir = args.transcriptDir ?? sessionTranscriptDir(args.projectDir);
|
|
8202
8311
|
let entries;
|
|
8203
8312
|
try {
|
|
8204
|
-
entries =
|
|
8313
|
+
entries = readdirSync8(dir);
|
|
8205
8314
|
} catch {
|
|
8206
8315
|
return UNKNOWN_RATE_LIMIT;
|
|
8207
8316
|
}
|
|
8208
8317
|
let newest = UNKNOWN_RATE_LIMIT;
|
|
8209
8318
|
for (const name of entries) {
|
|
8210
8319
|
if (!name.endsWith(".jsonl")) continue;
|
|
8211
|
-
const path =
|
|
8320
|
+
const path = join35(dir, name);
|
|
8212
8321
|
try {
|
|
8213
|
-
const st =
|
|
8322
|
+
const st = statSync8(path);
|
|
8214
8323
|
if (!st.isFile() || st.mtimeMs < startMs) continue;
|
|
8215
8324
|
} catch {
|
|
8216
8325
|
continue;
|
|
8217
8326
|
}
|
|
8218
8327
|
let content;
|
|
8219
8328
|
try {
|
|
8220
|
-
content =
|
|
8329
|
+
content = readFileSync27(path, "utf-8");
|
|
8221
8330
|
} catch {
|
|
8222
8331
|
continue;
|
|
8223
8332
|
}
|
|
@@ -8279,7 +8388,7 @@ function shouldLogUsageCapDeferral(site, codeName, limitedUntil) {
|
|
|
8279
8388
|
|
|
8280
8389
|
// src/lib/manager/scheduler/execution.ts
|
|
8281
8390
|
function claudePidFilePath() {
|
|
8282
|
-
return
|
|
8391
|
+
return join36(homedir15(), ".augmented", "manager-claude-pids.json");
|
|
8283
8392
|
}
|
|
8284
8393
|
var inFlightClaudePids = /* @__PURE__ */ new Map();
|
|
8285
8394
|
function registerClaudeSpawn(record) {
|
|
@@ -8299,10 +8408,10 @@ function unregisterClaudeSpawn(pid) {
|
|
|
8299
8408
|
}
|
|
8300
8409
|
async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData, durableScheduledNudge = false) {
|
|
8301
8410
|
const codeName = agent.code_name;
|
|
8302
|
-
const stableTasksHash =
|
|
8303
|
-
const boardHash = boardItems.length > 0 ?
|
|
8411
|
+
const stableTasksHash = createHash16("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
|
|
8412
|
+
const boardHash = boardItems.length > 0 ? createHash16("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";
|
|
8304
8413
|
const resolvedModels = resolveModelChain(refreshData);
|
|
8305
|
-
const modelsHash =
|
|
8414
|
+
const modelsHash = createHash16("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
|
|
8306
8415
|
const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
|
|
8307
8416
|
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
8308
8417
|
if (combinedHash !== prevHash) {
|
|
@@ -8349,8 +8458,8 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
8349
8458
|
}
|
|
8350
8459
|
|
|
8351
8460
|
// src/lib/occupancy-gate.ts
|
|
8352
|
-
import { closeSync as closeSync2, openSync as openSync2, readdirSync as
|
|
8353
|
-
import { join as
|
|
8461
|
+
import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync9, readSync as readSync2, statSync as statSync9 } from "fs";
|
|
8462
|
+
import { join as join37 } from "path";
|
|
8354
8463
|
function rostersMeasuredZero(mode, attested, runtimeRunning) {
|
|
8355
8464
|
return mode === "enforce" && attested && runtimeRunning;
|
|
8356
8465
|
}
|
|
@@ -8364,7 +8473,7 @@ var brackets = /* @__PURE__ */ new Map();
|
|
|
8364
8473
|
function readAlignedTail(path, tailBytes, maxAlignBytes) {
|
|
8365
8474
|
let fd = null;
|
|
8366
8475
|
try {
|
|
8367
|
-
const size =
|
|
8476
|
+
const size = statSync9(path).size;
|
|
8368
8477
|
if (size <= 0) return { content: "", complete: true, truncated: false };
|
|
8369
8478
|
fd = openSync2(path, "r");
|
|
8370
8479
|
let readStart = Math.max(0, size - tailBytes);
|
|
@@ -8434,26 +8543,26 @@ function candidateTranscriptPaths(dir) {
|
|
|
8434
8543
|
const paths = [];
|
|
8435
8544
|
let top;
|
|
8436
8545
|
try {
|
|
8437
|
-
top =
|
|
8546
|
+
top = readdirSync9(dir);
|
|
8438
8547
|
} catch {
|
|
8439
8548
|
return { paths, complete: false };
|
|
8440
8549
|
}
|
|
8441
8550
|
let complete = true;
|
|
8442
8551
|
for (const name of top) {
|
|
8443
8552
|
if (name.endsWith(".jsonl")) {
|
|
8444
|
-
paths.push(
|
|
8553
|
+
paths.push(join37(dir, name));
|
|
8445
8554
|
continue;
|
|
8446
8555
|
}
|
|
8447
|
-
const subDir =
|
|
8556
|
+
const subDir = join37(dir, name, "subagents");
|
|
8448
8557
|
let subs;
|
|
8449
8558
|
try {
|
|
8450
|
-
subs =
|
|
8559
|
+
subs = readdirSync9(subDir);
|
|
8451
8560
|
} catch (err) {
|
|
8452
8561
|
if (!isAbsentDirError(err)) complete = false;
|
|
8453
8562
|
continue;
|
|
8454
8563
|
}
|
|
8455
8564
|
for (const sub of subs) {
|
|
8456
|
-
if (sub.endsWith(".jsonl")) paths.push(
|
|
8565
|
+
if (sub.endsWith(".jsonl")) paths.push(join37(subDir, sub));
|
|
8457
8566
|
}
|
|
8458
8567
|
}
|
|
8459
8568
|
return { paths, complete };
|
|
@@ -8508,7 +8617,7 @@ function collectQualifyingTurns(codeName, nowMs, opts = {}) {
|
|
|
8508
8617
|
for (const path of paths) {
|
|
8509
8618
|
let st;
|
|
8510
8619
|
try {
|
|
8511
|
-
st =
|
|
8620
|
+
st = statSync9(path);
|
|
8512
8621
|
} catch (err) {
|
|
8513
8622
|
if (!isAbsentDirError(err)) complete = false;
|
|
8514
8623
|
continue;
|
|
@@ -8614,7 +8723,7 @@ function qualifyBuckets(buckets, qualifying, mode, nowMs, neighbourhoodMs = DEFA
|
|
|
8614
8723
|
}
|
|
8615
8724
|
|
|
8616
8725
|
// src/lib/pane-occupancy-sampler.ts
|
|
8617
|
-
import { statSync as
|
|
8726
|
+
import { statSync as statSync10 } from "fs";
|
|
8618
8727
|
var SAMPLE_INTERVAL_MS = 1e4;
|
|
8619
8728
|
var IDLE_GAP_MS = 12e4;
|
|
8620
8729
|
var POST_IDLE_CREDIT_MS = 6e4;
|
|
@@ -8628,7 +8737,7 @@ function hasFreshPaneObservation(codeName, nowMs, maxAgeMs = OBSERVATION_FRESH_M
|
|
|
8628
8737
|
}
|
|
8629
8738
|
function paneMtimeMs(codeName) {
|
|
8630
8739
|
try {
|
|
8631
|
-
return
|
|
8740
|
+
return statSync10(paneLogPath(codeName)).mtimeMs;
|
|
8632
8741
|
} catch {
|
|
8633
8742
|
return null;
|
|
8634
8743
|
}
|
|
@@ -8680,7 +8789,7 @@ function stopPaneOccupancySampler() {
|
|
|
8680
8789
|
|
|
8681
8790
|
// src/lib/pid-pressure-sampler.ts
|
|
8682
8791
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
8683
|
-
import { existsSync as
|
|
8792
|
+
import { existsSync as existsSync16, readFileSync as readFileSync28 } from "fs";
|
|
8684
8793
|
var SAMPLE_INTERVAL_MS2 = 3e4;
|
|
8685
8794
|
function warnFraction() {
|
|
8686
8795
|
const raw = Number(process.env.AGT_PID_PRESSURE_WARN_FRACTION);
|
|
@@ -8693,7 +8802,7 @@ function configuredCeiling() {
|
|
|
8693
8802
|
}
|
|
8694
8803
|
function readTextReal(path) {
|
|
8695
8804
|
try {
|
|
8696
|
-
return
|
|
8805
|
+
return readFileSync28(path, "utf-8");
|
|
8697
8806
|
} catch {
|
|
8698
8807
|
return null;
|
|
8699
8808
|
}
|
|
@@ -8702,7 +8811,7 @@ var cgroupDirCache = /* @__PURE__ */ new Map();
|
|
|
8702
8811
|
var resolveRetryAfter = /* @__PURE__ */ new Map();
|
|
8703
8812
|
var RESOLVE_RETRY_BACKOFF_MS = 5 * 6e4;
|
|
8704
8813
|
function resolveCgroupDirReal(codeName, deps = {}) {
|
|
8705
|
-
const exists = deps.exists ??
|
|
8814
|
+
const exists = deps.exists ?? existsSync16;
|
|
8706
8815
|
const inspectId = deps.inspectId ?? inspectContainerId;
|
|
8707
8816
|
const now = deps.now ?? Date.now;
|
|
8708
8817
|
const cached = cgroupDirCache.get(codeName);
|
|
@@ -8820,7 +8929,7 @@ function stopPidPressureSampler() {
|
|
|
8820
8929
|
}
|
|
8821
8930
|
|
|
8822
8931
|
// src/lib/opencode-slack-ingest.ts
|
|
8823
|
-
import { createHash as
|
|
8932
|
+
import { createHash as createHash17 } from "crypto";
|
|
8824
8933
|
|
|
8825
8934
|
// ../../packages/core/dist/channels/slack-rich-text.js
|
|
8826
8935
|
var MAX_DEPTH = 12;
|
|
@@ -9830,7 +9939,7 @@ function startSlackIngest(config2) {
|
|
|
9830
9939
|
// src/lib/opencode-slack-ingest.ts
|
|
9831
9940
|
var ingests = /* @__PURE__ */ new Map();
|
|
9832
9941
|
function fingerprint(params) {
|
|
9833
|
-
return
|
|
9942
|
+
return createHash17("sha256").update(
|
|
9834
9943
|
JSON.stringify({
|
|
9835
9944
|
appToken: params.appToken,
|
|
9836
9945
|
botToken: params.botToken,
|
|
@@ -9911,7 +10020,7 @@ function stopAllOpencodeSlackIngests(log2) {
|
|
|
9911
10020
|
}
|
|
9912
10021
|
|
|
9913
10022
|
// src/lib/manager/opencode-scheduler.ts
|
|
9914
|
-
import { createHash as
|
|
10023
|
+
import { createHash as createHash18 } from "crypto";
|
|
9915
10024
|
var MAX_OPENCODE_SCHED_CONCURRENCY = 2;
|
|
9916
10025
|
var opencodeSchedulerStates = /* @__PURE__ */ new Map();
|
|
9917
10026
|
var inFlightOpencodeTasks = /* @__PURE__ */ new Set();
|
|
@@ -9925,7 +10034,7 @@ function shouldDeliver(task, reply) {
|
|
|
9925
10034
|
}
|
|
9926
10035
|
async function syncAndCheckOpencodeScheduler(agent, tasks, refreshData) {
|
|
9927
10036
|
const codeName = agent.code_name;
|
|
9928
|
-
const tasksHash =
|
|
10037
|
+
const tasksHash = createHash18("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
|
|
9929
10038
|
if (knownOpencodeTaskHashes.get(agent.agent_id) !== tasksHash) {
|
|
9930
10039
|
const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
|
|
9931
10040
|
const state10 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
|
|
@@ -10003,10 +10112,10 @@ async function fireOpencodeScheduledTask(agent, task) {
|
|
|
10003
10112
|
}
|
|
10004
10113
|
|
|
10005
10114
|
// src/lib/opencode-telegram-ingest.ts
|
|
10006
|
-
import { createHash as
|
|
10007
|
-
import { existsSync as
|
|
10115
|
+
import { createHash as createHash19 } from "crypto";
|
|
10116
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync29, renameSync as renameSync9, unlinkSync as unlinkSync4, writeFileSync as writeFileSync15 } from "fs";
|
|
10008
10117
|
import { randomUUID } from "crypto";
|
|
10009
|
-
import { join as
|
|
10118
|
+
import { join as join38 } from "path";
|
|
10010
10119
|
|
|
10011
10120
|
// src/lib/telegram-ingest.ts
|
|
10012
10121
|
import https2 from "https";
|
|
@@ -10548,7 +10657,7 @@ function anySignal(signals) {
|
|
|
10548
10657
|
// src/lib/opencode-telegram-ingest.ts
|
|
10549
10658
|
var ingests2 = /* @__PURE__ */ new Map();
|
|
10550
10659
|
function fingerprint2(params) {
|
|
10551
|
-
return
|
|
10660
|
+
return createHash19("sha256").update(
|
|
10552
10661
|
JSON.stringify({
|
|
10553
10662
|
botToken: params.botToken,
|
|
10554
10663
|
allowedChats: [...params.allowedChats].sort(),
|
|
@@ -10563,7 +10672,7 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
|
|
|
10563
10672
|
let filePath;
|
|
10564
10673
|
try {
|
|
10565
10674
|
dir = getFramework("opencode").getAgentDir(codeName);
|
|
10566
|
-
filePath =
|
|
10675
|
+
filePath = join38(dir, "telegram-getupdates-offset-opencode.json");
|
|
10567
10676
|
} catch {
|
|
10568
10677
|
dir = null;
|
|
10569
10678
|
filePath = null;
|
|
@@ -10572,7 +10681,7 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
|
|
|
10572
10681
|
load() {
|
|
10573
10682
|
if (!filePath) return 0;
|
|
10574
10683
|
try {
|
|
10575
|
-
const parsed = JSON.parse(
|
|
10684
|
+
const parsed = JSON.parse(readFileSync29(filePath, "utf-8"));
|
|
10576
10685
|
if (currentBotId != null && typeof parsed?.bot_id === "number" && parsed.bot_id !== currentBotId) {
|
|
10577
10686
|
log2(`[telegram-ingest:${codeName}] offset cursor belongs to a different bot; ignoring (bot swap)`);
|
|
10578
10687
|
return 0;
|
|
@@ -10590,8 +10699,8 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
|
|
|
10590
10699
|
if (!filePath || !dir) return;
|
|
10591
10700
|
const tmpPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
10592
10701
|
try {
|
|
10593
|
-
|
|
10594
|
-
|
|
10702
|
+
mkdirSync11(dir, { recursive: true, mode: 448 });
|
|
10703
|
+
writeFileSync15(
|
|
10595
10704
|
tmpPath,
|
|
10596
10705
|
JSON.stringify({
|
|
10597
10706
|
offset,
|
|
@@ -10601,11 +10710,11 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
|
|
|
10601
10710
|
}),
|
|
10602
10711
|
{ mode: 384 }
|
|
10603
10712
|
);
|
|
10604
|
-
|
|
10713
|
+
renameSync9(tmpPath, filePath);
|
|
10605
10714
|
} catch (err) {
|
|
10606
10715
|
log2(`[telegram-ingest:${codeName}] offset persist failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
10607
10716
|
try {
|
|
10608
|
-
if (
|
|
10717
|
+
if (existsSync17(tmpPath)) unlinkSync4(tmpPath);
|
|
10609
10718
|
} catch {
|
|
10610
10719
|
}
|
|
10611
10720
|
}
|
|
@@ -10842,24 +10951,24 @@ function partitionActionableByPoison(actionable, states, config2) {
|
|
|
10842
10951
|
}
|
|
10843
10952
|
|
|
10844
10953
|
// src/lib/restart-flags.ts
|
|
10845
|
-
import { existsSync as
|
|
10954
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync12, readdirSync as readdirSync10, readFileSync as readFileSync30, renameSync as renameSync10, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "fs";
|
|
10846
10955
|
import { homedir as homedir16 } from "os";
|
|
10847
|
-
import { join as
|
|
10956
|
+
import { join as join39 } from "path";
|
|
10848
10957
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
10849
10958
|
function restartFlagsDir() {
|
|
10850
|
-
return
|
|
10959
|
+
return join39(homedir16(), ".augmented", "restart-flags");
|
|
10851
10960
|
}
|
|
10852
10961
|
function flagPath(codeName) {
|
|
10853
|
-
return
|
|
10962
|
+
return join39(restartFlagsDir(), `${codeName}.flag`);
|
|
10854
10963
|
}
|
|
10855
10964
|
function readRestartFlags() {
|
|
10856
10965
|
const dir = restartFlagsDir();
|
|
10857
|
-
if (!
|
|
10966
|
+
if (!existsSync18(dir)) return [];
|
|
10858
10967
|
const out = [];
|
|
10859
|
-
for (const entry of
|
|
10968
|
+
for (const entry of readdirSync10(dir)) {
|
|
10860
10969
|
if (!entry.endsWith(".flag")) continue;
|
|
10861
10970
|
try {
|
|
10862
|
-
const raw =
|
|
10971
|
+
const raw = readFileSync30(join39(dir, entry), "utf8");
|
|
10863
10972
|
const parsed = JSON.parse(raw);
|
|
10864
10973
|
if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
|
|
10865
10974
|
parsed.codeName = entry.replace(/\.flag$/, "");
|
|
@@ -10877,8 +10986,8 @@ function readRestartFlags() {
|
|
|
10877
10986
|
}
|
|
10878
10987
|
function deleteRestartFlag(codeName) {
|
|
10879
10988
|
const path = flagPath(codeName);
|
|
10880
|
-
if (
|
|
10881
|
-
|
|
10989
|
+
if (existsSync18(path)) {
|
|
10990
|
+
rmSync7(path, { force: true });
|
|
10882
10991
|
}
|
|
10883
10992
|
}
|
|
10884
10993
|
|
|
@@ -10977,8 +11086,8 @@ async function sendError(flag, opts, text) {
|
|
|
10977
11086
|
}
|
|
10978
11087
|
|
|
10979
11088
|
// src/lib/restart-context.ts
|
|
10980
|
-
import { readdirSync as
|
|
10981
|
-
import { dirname as dirname9, join as
|
|
11089
|
+
import { readdirSync as readdirSync11, readFileSync as readFileSync31, writeFileSync as writeFileSync17, mkdirSync as mkdirSync13, unlinkSync as unlinkSync5 } from "fs";
|
|
11090
|
+
import { dirname as dirname9, join as join40 } from "path";
|
|
10982
11091
|
var SLACK_PENDING_INBOUND_DIRNAME = "slack-pending-inbound";
|
|
10983
11092
|
var SLACK_RESTART_CONTEXT_DIRNAME = "slack-restart-context";
|
|
10984
11093
|
var MAX_TOPIC_CHARS = 140;
|
|
@@ -10990,10 +11099,10 @@ function augmentedAgentDir(codeName) {
|
|
|
10990
11099
|
return dirname9(getProjectDir(codeName));
|
|
10991
11100
|
}
|
|
10992
11101
|
function slackPendingInboundDir(codeName) {
|
|
10993
|
-
return
|
|
11102
|
+
return join40(augmentedAgentDir(codeName), SLACK_PENDING_INBOUND_DIRNAME);
|
|
10994
11103
|
}
|
|
10995
11104
|
function slackRestartContextDir(codeName) {
|
|
10996
|
-
return
|
|
11105
|
+
return join40(augmentedAgentDir(codeName), SLACK_RESTART_CONTEXT_DIRNAME);
|
|
10997
11106
|
}
|
|
10998
11107
|
function sanitizeTopic(raw) {
|
|
10999
11108
|
const cleaned = raw.replace(/\s+/g, " ").trim().replace(/[<>]/g, " ").replace(/\s+/g, " ").trim();
|
|
@@ -11028,14 +11137,14 @@ function computeRestartContextHints(markers, allTurns, nowMs, reconstruct = reco
|
|
|
11028
11137
|
}
|
|
11029
11138
|
function safeReaddir(dir) {
|
|
11030
11139
|
try {
|
|
11031
|
-
return
|
|
11140
|
+
return readdirSync11(dir);
|
|
11032
11141
|
} catch {
|
|
11033
11142
|
return [];
|
|
11034
11143
|
}
|
|
11035
11144
|
}
|
|
11036
11145
|
function readStrandedMarker(path) {
|
|
11037
11146
|
try {
|
|
11038
|
-
const parsed = JSON.parse(
|
|
11147
|
+
const parsed = JSON.parse(readFileSync31(path, "utf-8"));
|
|
11039
11148
|
if (typeof parsed.channel === "string" && typeof parsed.thread_ts === "string") {
|
|
11040
11149
|
return { channel: parsed.channel, thread_ts: parsed.thread_ts };
|
|
11041
11150
|
}
|
|
@@ -11044,8 +11153,8 @@ function readStrandedMarker(path) {
|
|
|
11044
11153
|
return null;
|
|
11045
11154
|
}
|
|
11046
11155
|
function writeHintFile(path, dir, hint) {
|
|
11047
|
-
|
|
11048
|
-
|
|
11156
|
+
mkdirSync13(dir, { recursive: true, mode: 448 });
|
|
11157
|
+
writeFileSync17(path, JSON.stringify(hint), { mode: 384 });
|
|
11049
11158
|
}
|
|
11050
11159
|
function pruneHintsExcept(codeName, freshFilenames) {
|
|
11051
11160
|
const ctxDir = slackRestartContextDir(codeName);
|
|
@@ -11053,7 +11162,7 @@ function pruneHintsExcept(codeName, freshFilenames) {
|
|
|
11053
11162
|
if (!filename.endsWith(".json")) continue;
|
|
11054
11163
|
if (freshFilenames.has(filename)) continue;
|
|
11055
11164
|
try {
|
|
11056
|
-
unlinkSync5(
|
|
11165
|
+
unlinkSync5(join40(ctxDir, filename));
|
|
11057
11166
|
} catch {
|
|
11058
11167
|
}
|
|
11059
11168
|
}
|
|
@@ -11074,7 +11183,7 @@ function refreshSlackRestartContextHints(codeNames, opts = {}) {
|
|
|
11074
11183
|
}
|
|
11075
11184
|
const markers = [];
|
|
11076
11185
|
for (const filename of markerFilenames.slice(0, cap)) {
|
|
11077
|
-
const parsed = readStrandedMarker(
|
|
11186
|
+
const parsed = readStrandedMarker(join40(markerDir, filename));
|
|
11078
11187
|
if (parsed) markers.push({ filename, channel: parsed.channel, thread_ts: parsed.thread_ts });
|
|
11079
11188
|
}
|
|
11080
11189
|
if (markers.length === 0) {
|
|
@@ -11088,7 +11197,7 @@ function refreshSlackRestartContextHints(codeNames, opts = {}) {
|
|
|
11088
11197
|
const freshFilenames = /* @__PURE__ */ new Set();
|
|
11089
11198
|
for (const { filename, hint } of hints) {
|
|
11090
11199
|
try {
|
|
11091
|
-
writeHintFile(
|
|
11200
|
+
writeHintFile(join40(ctxDir, filename), ctxDir, hint);
|
|
11092
11201
|
freshFilenames.add(filename);
|
|
11093
11202
|
} catch (err) {
|
|
11094
11203
|
log2(`[restart-context] ${codeName}: hint write failed for ${filename}: ${err.message}`);
|
|
@@ -12622,7 +12731,7 @@ function performLazyDayRolloverReset(codeName, agentTimezone) {
|
|
|
12622
12731
|
}
|
|
12623
12732
|
function paneLogAgeSecondsFor(codeName) {
|
|
12624
12733
|
try {
|
|
12625
|
-
const mtimeMs =
|
|
12734
|
+
const mtimeMs = statSync11(paneLogPath(codeName)).mtimeMs;
|
|
12626
12735
|
return Math.max(0, Math.floor((Date.now() - mtimeMs) / 1e3));
|
|
12627
12736
|
} catch (err) {
|
|
12628
12737
|
if (err?.code === "ENOENT") return null;
|
|
@@ -12772,15 +12881,15 @@ var runningChannelSecretHashes = /* @__PURE__ */ new Map();
|
|
|
12772
12881
|
var sessionLaunchManagedStructure = /* @__PURE__ */ new Map();
|
|
12773
12882
|
function projectMcpHash(_codeName, projectDir) {
|
|
12774
12883
|
try {
|
|
12775
|
-
const raw =
|
|
12776
|
-
return
|
|
12884
|
+
const raw = readFileSync32(join41(projectDir, ".mcp.json"), "utf-8");
|
|
12885
|
+
return createHash20("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
|
|
12777
12886
|
} catch {
|
|
12778
12887
|
return null;
|
|
12779
12888
|
}
|
|
12780
12889
|
}
|
|
12781
12890
|
function projectMcpKeys(_codeName, projectDir) {
|
|
12782
12891
|
try {
|
|
12783
|
-
const raw =
|
|
12892
|
+
const raw = readFileSync32(join41(projectDir, ".mcp.json"), "utf-8");
|
|
12784
12893
|
const parsed = JSON.parse(raw);
|
|
12785
12894
|
const servers = parsed.mcpServers;
|
|
12786
12895
|
if (!servers || typeof servers !== "object") return /* @__PURE__ */ new Set();
|
|
@@ -12798,7 +12907,7 @@ function seedSessionLaunchBaselines(codeName, projectDir) {
|
|
|
12798
12907
|
else runningMcpServerKeys.delete(codeName);
|
|
12799
12908
|
let launchStructure = null;
|
|
12800
12909
|
try {
|
|
12801
|
-
const raw =
|
|
12910
|
+
const raw = readFileSync32(join41(projectDir, ".mcp.json"), "utf-8");
|
|
12802
12911
|
launchStructure = managedMcpStructureHashFromFile(
|
|
12803
12912
|
JSON.parse(raw),
|
|
12804
12913
|
isManagedMcpServerKey
|
|
@@ -12924,7 +13033,7 @@ async function runAgentSessionToolBindProbes(agent, integrations, projectDir, op
|
|
|
12924
13033
|
if (result && result.rebindCandidates.length > 0 && hostFlagStore().getBoolean("session-tool-rebind")) {
|
|
12925
13034
|
let mcpJsonForRebind = null;
|
|
12926
13035
|
try {
|
|
12927
|
-
mcpJsonForRebind = JSON.parse(
|
|
13036
|
+
mcpJsonForRebind = JSON.parse(readFileSync32(join41(projectDir, ".mcp.json"), "utf-8"));
|
|
12928
13037
|
} catch {
|
|
12929
13038
|
mcpJsonForRebind = null;
|
|
12930
13039
|
}
|
|
@@ -13072,7 +13181,7 @@ function shouldInjectChannelSecrets(agentId) {
|
|
|
13072
13181
|
function projectChannelSecretHash(projectDir) {
|
|
13073
13182
|
try {
|
|
13074
13183
|
const entries = parseEnvIntegrations(
|
|
13075
|
-
|
|
13184
|
+
readFileSync32(join41(projectDir, ".env.integrations"), "utf-8")
|
|
13076
13185
|
);
|
|
13077
13186
|
return channelSecretValueHash(entries, CHANNEL_SECRET_ENV_KEYS);
|
|
13078
13187
|
} catch {
|
|
@@ -13175,7 +13284,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
13175
13284
|
var lastVersionCheckAt = 0;
|
|
13176
13285
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
13177
13286
|
var lastResponsivenessProbeAt = 0;
|
|
13178
|
-
var agtCliVersion = true ? "0.28.
|
|
13287
|
+
var agtCliVersion = true ? "0.28.745" : "dev";
|
|
13179
13288
|
function resolveBrewPath(execFileSync3) {
|
|
13180
13289
|
try {
|
|
13181
13290
|
const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -13188,7 +13297,7 @@ function resolveBrewPath(execFileSync3) {
|
|
|
13188
13297
|
"/usr/local/bin/brew"
|
|
13189
13298
|
];
|
|
13190
13299
|
for (const path of fallbacks) {
|
|
13191
|
-
if (
|
|
13300
|
+
if (existsSync19(path)) return path;
|
|
13192
13301
|
}
|
|
13193
13302
|
return null;
|
|
13194
13303
|
}
|
|
@@ -13198,7 +13307,7 @@ function claudeBinaryInstalled(execFileSync3) {
|
|
|
13198
13307
|
"/opt/homebrew/bin/claude",
|
|
13199
13308
|
"/usr/local/bin/claude"
|
|
13200
13309
|
];
|
|
13201
|
-
if (canonical.some((path) =>
|
|
13310
|
+
if (canonical.some((path) => existsSync19(path))) return true;
|
|
13202
13311
|
try {
|
|
13203
13312
|
execFileSync3("which", ["claude"], { timeout: 5e3 });
|
|
13204
13313
|
return true;
|
|
@@ -13508,8 +13617,8 @@ var MANAGED_SETTINGS_KEYS = ["channelsEnabled", "enableAllProjectMcpServers"];
|
|
|
13508
13617
|
function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
|
|
13509
13618
|
try {
|
|
13510
13619
|
let settings = {};
|
|
13511
|
-
if (
|
|
13512
|
-
const raw =
|
|
13620
|
+
if (existsSync19(path)) {
|
|
13621
|
+
const raw = readFileSync32(path, "utf-8").trim();
|
|
13513
13622
|
if (raw) {
|
|
13514
13623
|
let parsed;
|
|
13515
13624
|
try {
|
|
@@ -13526,8 +13635,8 @@ function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
|
|
|
13526
13635
|
const missing = MANAGED_SETTINGS_KEYS.filter((key) => settings[key] !== true);
|
|
13527
13636
|
if (missing.length === 0) return "ok";
|
|
13528
13637
|
for (const key of missing) settings[key] = true;
|
|
13529
|
-
|
|
13530
|
-
|
|
13638
|
+
mkdirSync14(dirname10(path), { recursive: true });
|
|
13639
|
+
writeFileSync18(path, `${JSON.stringify(settings, null, 2)}
|
|
13531
13640
|
`);
|
|
13532
13641
|
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)`);
|
|
13533
13642
|
return "ok";
|
|
@@ -13565,7 +13674,7 @@ async function ensureOpencodeBinary() {
|
|
|
13565
13674
|
try {
|
|
13566
13675
|
const prefix = execFileSync3("npm", ["prefix", "-g"], { encoding: "utf-8", timeout: 1e4 }).trim();
|
|
13567
13676
|
if (prefix) {
|
|
13568
|
-
const npmBin =
|
|
13677
|
+
const npmBin = join41(prefix, "bin");
|
|
13569
13678
|
const current = (process.env.PATH ?? "").split(pathDelimiter);
|
|
13570
13679
|
if (!current.includes(npmBin)) {
|
|
13571
13680
|
process.env.PATH = [npmBin, ...current.filter(Boolean)].join(pathDelimiter);
|
|
@@ -13626,7 +13735,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
13626
13735
|
if (!process.env.PATH?.split(":").includes(brewBinDir)) {
|
|
13627
13736
|
process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
|
|
13628
13737
|
}
|
|
13629
|
-
if (
|
|
13738
|
+
if (existsSync19("/home/linuxbrew/.linuxbrew/bin/claude")) {
|
|
13630
13739
|
log("Claude Code installed successfully");
|
|
13631
13740
|
} else {
|
|
13632
13741
|
log("Claude Code install completed but binary not found at expected path \u2014 check brew logs");
|
|
@@ -13682,7 +13791,7 @@ ${r.stderr}`;
|
|
|
13682
13791
|
}
|
|
13683
13792
|
var UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
13684
13793
|
function selfUpdateAppliedMarkerPath() {
|
|
13685
|
-
return
|
|
13794
|
+
return join41(homedir17(), ".augmented", ".last-self-update-applied");
|
|
13686
13795
|
}
|
|
13687
13796
|
var selfUpdateUpToDateLogged = false;
|
|
13688
13797
|
var selfUpdatePinnedLogged = false;
|
|
@@ -13733,7 +13842,7 @@ async function checkAndUpdateCli(opts) {
|
|
|
13733
13842
|
const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
|
|
13734
13843
|
if (!isBrewFormula && !isNpmGlobal) return "noop";
|
|
13735
13844
|
const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
|
|
13736
|
-
const markerPath =
|
|
13845
|
+
const markerPath = join41(homedir17(), ".augmented", ".last-update-check");
|
|
13737
13846
|
if (!force) {
|
|
13738
13847
|
try {
|
|
13739
13848
|
const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
|
|
@@ -14226,14 +14335,14 @@ async function checkClaudeAuth() {
|
|
|
14226
14335
|
}
|
|
14227
14336
|
var evalEmptyMcpConfigPath = null;
|
|
14228
14337
|
function ensureEvalEmptyMcpConfig() {
|
|
14229
|
-
if (evalEmptyMcpConfigPath &&
|
|
14230
|
-
const dir =
|
|
14338
|
+
if (evalEmptyMcpConfigPath && existsSync19(evalEmptyMcpConfigPath)) return evalEmptyMcpConfigPath;
|
|
14339
|
+
const dir = join41(homedir17(), ".augmented");
|
|
14231
14340
|
try {
|
|
14232
|
-
|
|
14341
|
+
mkdirSync14(dir, { recursive: true });
|
|
14233
14342
|
} catch {
|
|
14234
14343
|
}
|
|
14235
|
-
const p =
|
|
14236
|
-
|
|
14344
|
+
const p = join41(dir, ".eval-empty-mcp.json");
|
|
14345
|
+
writeFileSync18(p, JSON.stringify({ mcpServers: {} }));
|
|
14237
14346
|
evalEmptyMcpConfigPath = p;
|
|
14238
14347
|
return p;
|
|
14239
14348
|
}
|
|
@@ -14327,10 +14436,10 @@ function resolveConversationEvalBackend() {
|
|
|
14327
14436
|
return conversationEvalBackend;
|
|
14328
14437
|
}
|
|
14329
14438
|
function getStateFile() {
|
|
14330
|
-
return
|
|
14439
|
+
return join41(config?.configDir ?? join41(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
|
|
14331
14440
|
}
|
|
14332
14441
|
function channelHashCacheDir() {
|
|
14333
|
-
return config?.configDir ??
|
|
14442
|
+
return config?.configDir ?? join41(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
14334
14443
|
}
|
|
14335
14444
|
function loadChannelHashCache2() {
|
|
14336
14445
|
loadChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
|
|
@@ -14537,7 +14646,7 @@ function removeDeliveryBaselineEntries(agentId) {
|
|
|
14537
14646
|
var _channelQuarantineStore = null;
|
|
14538
14647
|
function channelQuarantineStore() {
|
|
14539
14648
|
if (!_channelQuarantineStore) {
|
|
14540
|
-
const dir = config?.configDir ??
|
|
14649
|
+
const dir = config?.configDir ?? join41(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
14541
14650
|
_channelQuarantineStore = new ChannelQuarantineStore(defaultQuarantinePath(dir));
|
|
14542
14651
|
}
|
|
14543
14652
|
return _channelQuarantineStore;
|
|
@@ -14553,12 +14662,12 @@ function claudeMdSizeFor(codeName) {
|
|
|
14553
14662
|
}
|
|
14554
14663
|
function forwardedToolsFor(codeName) {
|
|
14555
14664
|
if (!config?.configDir) return null;
|
|
14556
|
-
return readForwardedToolsReport(
|
|
14665
|
+
return readForwardedToolsReport(join41(config.configDir, codeName));
|
|
14557
14666
|
}
|
|
14558
14667
|
var _hostFlagStore = null;
|
|
14559
14668
|
function hostFlagStore() {
|
|
14560
14669
|
if (!_hostFlagStore) {
|
|
14561
|
-
const dir = config?.configDir ??
|
|
14670
|
+
const dir = config?.configDir ?? join41(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
14562
14671
|
_hostFlagStore = new HostFlagStore({ cachePath: defaultFlagsCachePath(dir), log });
|
|
14563
14672
|
}
|
|
14564
14673
|
return _hostFlagStore;
|
|
@@ -14631,13 +14740,13 @@ function parseSkillFrontmatter(content) {
|
|
|
14631
14740
|
return out;
|
|
14632
14741
|
}
|
|
14633
14742
|
async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
|
|
14634
|
-
const { readdirSync:
|
|
14635
|
-
const skillsDir =
|
|
14636
|
-
const claudeMdPath =
|
|
14743
|
+
const { readdirSync: readdirSync13, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync19 } = await import("fs");
|
|
14744
|
+
const skillsDir = join41(configDir, codeName, "project", ".claude", "skills");
|
|
14745
|
+
const claudeMdPath = join41(configDir, codeName, "project", "CLAUDE.md");
|
|
14637
14746
|
if (!ex(skillsDir) || !ex(claudeMdPath)) return;
|
|
14638
14747
|
const entries = [];
|
|
14639
|
-
for (const dir of
|
|
14640
|
-
const skillFile =
|
|
14748
|
+
for (const dir of readdirSync13(skillsDir).sort()) {
|
|
14749
|
+
const skillFile = join41(skillsDir, dir, "SKILL.md");
|
|
14641
14750
|
if (!ex(skillFile)) continue;
|
|
14642
14751
|
try {
|
|
14643
14752
|
const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
|
|
@@ -14681,7 +14790,7 @@ ${SKILLS_INDEX_END}`;
|
|
|
14681
14790
|
next = current.trimEnd() + "\n\n" + section + "\n";
|
|
14682
14791
|
}
|
|
14683
14792
|
if (next !== current) {
|
|
14684
|
-
|
|
14793
|
+
writeFileSync19(claudeMdPath, next, "utf-8");
|
|
14685
14794
|
log2(
|
|
14686
14795
|
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)`
|
|
14687
14796
|
);
|
|
@@ -14887,7 +14996,7 @@ async function pollCycleInner() {
|
|
|
14887
14996
|
claudeAuth = await detectClaudeAuth();
|
|
14888
14997
|
} catch (err) {
|
|
14889
14998
|
const errText = err instanceof Error ? err.message : String(err);
|
|
14890
|
-
const errId =
|
|
14999
|
+
const errId = createHash20("sha256").update(errText).digest("hex").slice(0, 12);
|
|
14891
15000
|
log(`Claude auth detection failed (error_id=${errId})`);
|
|
14892
15001
|
}
|
|
14893
15002
|
const hostHasClaudeCode = state8.agents.some(
|
|
@@ -15225,13 +15334,13 @@ async function pollCycleInner() {
|
|
|
15225
15334
|
);
|
|
15226
15335
|
if (hostFlagStore().getBoolean("wedge-transient-notice")) {
|
|
15227
15336
|
try {
|
|
15228
|
-
const paneTail =
|
|
15337
|
+
const paneTail = readFileSync32(paneLogPath(codeName), "utf8").slice(-65536);
|
|
15229
15338
|
const transient = detectTransientApiErrorInLog(paneTail);
|
|
15230
15339
|
if (transient) {
|
|
15231
|
-
const wedgeHome =
|
|
15232
|
-
if (
|
|
15340
|
+
const wedgeHome = join41(homedir17(), ".augmented", codeName);
|
|
15341
|
+
if (existsSync19(wedgeHome)) {
|
|
15233
15342
|
atomicWriteFileSync(
|
|
15234
|
-
|
|
15343
|
+
join41(wedgeHome, "watchdog-give-up.json"),
|
|
15235
15344
|
JSON.stringify({
|
|
15236
15345
|
gave_up_at: wedgeNow.toISOString(),
|
|
15237
15346
|
reason: "transient_overload"
|
|
@@ -15557,7 +15666,7 @@ async function pollCycleInner() {
|
|
|
15557
15666
|
`[drain-flush] FAILED for '${prev.codeName}': ${err.message} \u2014 proceeding to teardown; this session was NOT shipped (ENG-9491)`
|
|
15558
15667
|
);
|
|
15559
15668
|
}
|
|
15560
|
-
const agentDir =
|
|
15669
|
+
const agentDir = join41(adapter.getAgentDir(prev.codeName), "provision");
|
|
15561
15670
|
await cleanupAgentFiles(prev.codeName, agentDir);
|
|
15562
15671
|
clearAgentCaches(prev.agentId, prev.codeName);
|
|
15563
15672
|
}
|
|
@@ -15644,10 +15753,10 @@ async function pollCycleInner() {
|
|
|
15644
15753
|
// pending-inbound marker. Best-effort: a write failure is logged by
|
|
15645
15754
|
// the watchdog, never fails the poll cycle.
|
|
15646
15755
|
signalGiveUp: (codeName) => {
|
|
15647
|
-
const dir =
|
|
15648
|
-
if (!
|
|
15756
|
+
const dir = join41(homedir17(), ".augmented", codeName);
|
|
15757
|
+
if (!existsSync19(dir)) return;
|
|
15649
15758
|
atomicWriteFileSync(
|
|
15650
|
-
|
|
15759
|
+
join41(dir, "watchdog-give-up.json"),
|
|
15651
15760
|
JSON.stringify({ gave_up_at: (/* @__PURE__ */ new Date()).toISOString() })
|
|
15652
15761
|
);
|
|
15653
15762
|
},
|
|
@@ -15666,9 +15775,9 @@ async function pollCycleInner() {
|
|
|
15666
15775
|
// parser elsewhere can only reconstruct an hour (ENG-8901).
|
|
15667
15776
|
signalUsageLimit: (codeName, resetsHint) => {
|
|
15668
15777
|
const dir = getFramework("claude-code").getAgentDir(codeName);
|
|
15669
|
-
if (!
|
|
15778
|
+
if (!existsSync19(dir)) return;
|
|
15670
15779
|
atomicWriteFileSync(
|
|
15671
|
-
|
|
15780
|
+
join41(dir, "watchdog-give-up.json"),
|
|
15672
15781
|
JSON.stringify({
|
|
15673
15782
|
gave_up_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15674
15783
|
reason: "usage_limit",
|
|
@@ -15930,7 +16039,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
15930
16039
|
}
|
|
15931
16040
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15932
16041
|
const adapter = resolveAgentFramework(agent.code_name);
|
|
15933
|
-
let agentDir =
|
|
16042
|
+
let agentDir = join41(adapter.getAgentDir(agent.code_name), "provision");
|
|
15934
16043
|
if (agent.status === "draft" || agent.status === "paused") {
|
|
15935
16044
|
forgetChannelSyncState(agent.agent_id);
|
|
15936
16045
|
if (previousKnownStatus !== agent.status) {
|
|
@@ -15971,7 +16080,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
15971
16080
|
const residuals = {
|
|
15972
16081
|
gatewayRunning: false,
|
|
15973
16082
|
portAllocated: false,
|
|
15974
|
-
provisionDirExists:
|
|
16083
|
+
provisionDirExists: existsSync19(agentDir)
|
|
15975
16084
|
};
|
|
15976
16085
|
if (!hasRevokedResiduals(residuals)) {
|
|
15977
16086
|
agentStates.push({
|
|
@@ -16077,7 +16186,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16077
16186
|
if (refreshData.knowledge_manifest) {
|
|
16078
16187
|
const resolved = await resolveKnowledgeFromManifest({
|
|
16079
16188
|
manifest: refreshData.knowledge_manifest,
|
|
16080
|
-
cacheDir:
|
|
16189
|
+
cacheDir: join41(config.configDir, "_knowledge"),
|
|
16081
16190
|
delivery: refreshData.agent?.knowledge_delivery ?? "both",
|
|
16082
16191
|
fetchContents: async (hashes) => {
|
|
16083
16192
|
const res = await api.post(
|
|
@@ -16094,7 +16203,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16094
16203
|
const resolvedSkills = await resolveSkillsFromManifest({
|
|
16095
16204
|
globals: refreshData.global_skills_manifest ?? [],
|
|
16096
16205
|
shared: refreshData.shared_skills_manifest ?? [],
|
|
16097
|
-
cacheDir:
|
|
16206
|
+
cacheDir: join41(config.configDir, "_skills"),
|
|
16098
16207
|
fetchContents: async (hashes) => {
|
|
16099
16208
|
const res = await api.post(
|
|
16100
16209
|
"/host/skills/contents",
|
|
@@ -16112,7 +16221,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16112
16221
|
if (refreshData.integration_skills_manifest) {
|
|
16113
16222
|
const resolvedIntegrationSkills = await resolveIntegrationSkillsFromManifest({
|
|
16114
16223
|
manifest: refreshData.integration_skills_manifest,
|
|
16115
|
-
cacheDir:
|
|
16224
|
+
cacheDir: join41(config.configDir, "_skills"),
|
|
16116
16225
|
fetchContents: async (hashes) => {
|
|
16117
16226
|
const res = await api.post(
|
|
16118
16227
|
"/host/skills/contents",
|
|
@@ -16174,7 +16283,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16174
16283
|
const frameworkId = refreshData.agent.framework ?? DEFAULT_FRAMEWORK;
|
|
16175
16284
|
agentFrameworkCache.set(agent.code_name, frameworkId);
|
|
16176
16285
|
const frameworkAdapter = getFramework(frameworkId);
|
|
16177
|
-
agentDir =
|
|
16286
|
+
agentDir = join41(frameworkAdapter.getAgentDir(agent.code_name), "provision");
|
|
16178
16287
|
cacheAgentDeliveryMetadata(agent.code_name, refreshData);
|
|
16179
16288
|
agentRestartTimezoneInputs.set(agent.code_name, {
|
|
16180
16289
|
agentTimezone: typeof refreshData.agent.timezone === "string" ? refreshData.agent.timezone : null,
|
|
@@ -16230,9 +16339,9 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16230
16339
|
try {
|
|
16231
16340
|
const artifacts = generateArtifacts(agent, refreshData, frameworkAdapter, renderIntegrationsSection);
|
|
16232
16341
|
const changedFiles = [];
|
|
16233
|
-
|
|
16342
|
+
mkdirSync14(agentDir, { recursive: true });
|
|
16234
16343
|
for (const artifact of artifacts) {
|
|
16235
|
-
const filePath =
|
|
16344
|
+
const filePath = join41(agentDir, artifact.relativePath);
|
|
16236
16345
|
let existingHash;
|
|
16237
16346
|
let newHash;
|
|
16238
16347
|
let writeContent = artifact.content;
|
|
@@ -16251,8 +16360,8 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16251
16360
|
};
|
|
16252
16361
|
newHash = sha256(stripDynamicSections(artifact.content));
|
|
16253
16362
|
try {
|
|
16254
|
-
const projectClaudeMd =
|
|
16255
|
-
const existing =
|
|
16363
|
+
const projectClaudeMd = join41(config.configDir, agent.code_name, "project", "CLAUDE.md");
|
|
16364
|
+
const existing = readFileSync32(projectClaudeMd, "utf-8");
|
|
16256
16365
|
existingHash = sha256(stripDynamicSections(existing));
|
|
16257
16366
|
} catch {
|
|
16258
16367
|
existingHash = null;
|
|
@@ -16270,7 +16379,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16270
16379
|
const generatorKeys = Object.keys(generatorServers);
|
|
16271
16380
|
let existingRaw = "";
|
|
16272
16381
|
try {
|
|
16273
|
-
existingRaw =
|
|
16382
|
+
existingRaw = readFileSync32(filePath, "utf-8");
|
|
16274
16383
|
} catch {
|
|
16275
16384
|
}
|
|
16276
16385
|
const existingServers = parseMcp(existingRaw);
|
|
@@ -16286,7 +16395,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16286
16395
|
} else if (artifact.relativePath === "opencode.json") {
|
|
16287
16396
|
let existingRaw = null;
|
|
16288
16397
|
try {
|
|
16289
|
-
existingRaw =
|
|
16398
|
+
existingRaw = readFileSync32(filePath, "utf-8");
|
|
16290
16399
|
} catch {
|
|
16291
16400
|
}
|
|
16292
16401
|
const mergeResult = mergeOpencodeConfigArtifact(artifact.content, existingRaw);
|
|
@@ -16302,26 +16411,26 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16302
16411
|
}
|
|
16303
16412
|
}
|
|
16304
16413
|
if (changedFiles.length > 0) {
|
|
16305
|
-
const isFirst = !
|
|
16414
|
+
const isFirst = !existsSync19(join41(agentDir, "CHARTER.md"));
|
|
16306
16415
|
const verb = isFirst ? "Provisioning" : "Updating";
|
|
16307
16416
|
const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
|
|
16308
16417
|
log(`${verb} '${agent.code_name}': ${fileNames}`);
|
|
16309
16418
|
for (const file of changedFiles) {
|
|
16310
|
-
const filePath =
|
|
16311
|
-
|
|
16419
|
+
const filePath = join41(agentDir, file.relativePath);
|
|
16420
|
+
mkdirSync14(dirname10(filePath), { recursive: true });
|
|
16312
16421
|
if (file.relativePath === ".mcp.json") {
|
|
16313
16422
|
safeWriteJsonAtomic(filePath, file.content, { mode: 384 });
|
|
16314
16423
|
} else {
|
|
16315
|
-
|
|
16424
|
+
writeFileSync18(filePath, file.content);
|
|
16316
16425
|
}
|
|
16317
16426
|
}
|
|
16318
16427
|
try {
|
|
16319
|
-
const provSkillsDir =
|
|
16320
|
-
if (
|
|
16321
|
-
for (const folder of
|
|
16428
|
+
const provSkillsDir = join41(agentDir, ".claude", "skills");
|
|
16429
|
+
if (existsSync19(provSkillsDir)) {
|
|
16430
|
+
for (const folder of readdirSync12(provSkillsDir)) {
|
|
16322
16431
|
if (folder.startsWith("knowledge-")) {
|
|
16323
16432
|
try {
|
|
16324
|
-
|
|
16433
|
+
rmSync8(join41(provSkillsDir, folder), { recursive: true });
|
|
16325
16434
|
} catch {
|
|
16326
16435
|
}
|
|
16327
16436
|
}
|
|
@@ -16334,7 +16443,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16334
16443
|
const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
|
|
16335
16444
|
const hashes = /* @__PURE__ */ new Map();
|
|
16336
16445
|
for (const file of trackedFiles2) {
|
|
16337
|
-
const h = hashFile(
|
|
16446
|
+
const h = hashFile(join41(agentDir, file));
|
|
16338
16447
|
if (h) hashes.set(file, h);
|
|
16339
16448
|
}
|
|
16340
16449
|
agentState.writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -16352,14 +16461,14 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16352
16461
|
}
|
|
16353
16462
|
if (Array.isArray(refreshData.workflows)) {
|
|
16354
16463
|
try {
|
|
16355
|
-
const provWorkflowsDir =
|
|
16356
|
-
if (
|
|
16464
|
+
const provWorkflowsDir = join41(agentDir, ".claude", "workflows");
|
|
16465
|
+
if (existsSync19(provWorkflowsDir)) {
|
|
16357
16466
|
const expected = new Set(refreshData.workflows.map((w) => `${w.name}.js`));
|
|
16358
|
-
for (const file of
|
|
16467
|
+
for (const file of readdirSync12(provWorkflowsDir)) {
|
|
16359
16468
|
if (!file.endsWith(".js")) continue;
|
|
16360
16469
|
if (expected.has(file)) continue;
|
|
16361
16470
|
try {
|
|
16362
|
-
|
|
16471
|
+
rmSync8(join41(provWorkflowsDir, file));
|
|
16363
16472
|
} catch {
|
|
16364
16473
|
}
|
|
16365
16474
|
}
|
|
@@ -16438,10 +16547,10 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16438
16547
|
}
|
|
16439
16548
|
let lastDriftCheckAt = now;
|
|
16440
16549
|
const written = agentState.writtenHashes.get(agent.agent_id);
|
|
16441
|
-
if (written &&
|
|
16550
|
+
if (written && existsSync19(agentDir)) {
|
|
16442
16551
|
const driftedFiles = [];
|
|
16443
16552
|
for (const [file, expectedHash] of written) {
|
|
16444
|
-
const localHash = hashFile(
|
|
16553
|
+
const localHash = hashFile(join41(agentDir, file));
|
|
16445
16554
|
if (localHash && localHash !== expectedHash) {
|
|
16446
16555
|
driftedFiles.push(file);
|
|
16447
16556
|
}
|
|
@@ -16452,7 +16561,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16452
16561
|
try {
|
|
16453
16562
|
const localHashes = {};
|
|
16454
16563
|
for (const file of driftedFiles) {
|
|
16455
|
-
localHashes[file] = hashFile(
|
|
16564
|
+
localHashes[file] = hashFile(join41(agentDir, file));
|
|
16456
16565
|
}
|
|
16457
16566
|
await api.post("/host/drift", {
|
|
16458
16567
|
agent_id: agent.agent_id,
|
|
@@ -16733,15 +16842,15 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16733
16842
|
const addedChannels = [...restartDecision.added];
|
|
16734
16843
|
const writeDmNoticeMarkers = isChannelAddRestart ? () => {
|
|
16735
16844
|
try {
|
|
16736
|
-
const agentAugmentedDir =
|
|
16737
|
-
|
|
16845
|
+
const agentAugmentedDir = join41(homedir17(), ".augmented", agent.code_name);
|
|
16846
|
+
mkdirSync14(agentAugmentedDir, { recursive: true });
|
|
16738
16847
|
const markerJson = JSON.stringify({
|
|
16739
16848
|
version: 1,
|
|
16740
16849
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16741
16850
|
added: addedChannels
|
|
16742
16851
|
});
|
|
16743
16852
|
for (const file of ["slack-channel-add-restart.json", "telegram-channel-add-restart.json"]) {
|
|
16744
|
-
atomicWriteFileSync(
|
|
16853
|
+
atomicWriteFileSync(join41(agentAugmentedDir, file), markerJson);
|
|
16745
16854
|
}
|
|
16746
16855
|
} catch (err) {
|
|
16747
16856
|
log(`[hot-reload] channel-add DM-notice marker write failed for '${agent.code_name}' (non-fatal): ${err.message}`);
|
|
@@ -16817,7 +16926,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16817
16926
|
const behaviourSubset = extractMsTeamsBehaviourSubset(
|
|
16818
16927
|
msteamsEntry?.config
|
|
16819
16928
|
);
|
|
16820
|
-
const behaviourHash =
|
|
16929
|
+
const behaviourHash = createHash20("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
|
|
16821
16930
|
const prevBehaviourHash = agentState.knownMsTeamsBehaviourHashes.get(agent.agent_id);
|
|
16822
16931
|
const msteamsBehaviourRestrictive = isMsTeamsBehaviourRestrictive(behaviourSubset);
|
|
16823
16932
|
const behaviourDecision = decideSenderPolicyRestart({
|
|
@@ -16873,7 +16982,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16873
16982
|
const slackBehaviourSubset = extractSlackBehaviourSubset(
|
|
16874
16983
|
slackEntry?.config
|
|
16875
16984
|
);
|
|
16876
|
-
const slackBehaviourHash =
|
|
16985
|
+
const slackBehaviourHash = createHash20("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
|
|
16877
16986
|
const prevSlackBehaviourHash = agentState.knownSlackBehaviourHashes.get(agent.agent_id);
|
|
16878
16987
|
const slackBehaviourRestrictive = isSlackBehaviourRestrictive(slackBehaviourSubset);
|
|
16879
16988
|
const slackBehaviourDecision = decideSenderPolicyRestart({
|
|
@@ -16930,24 +17039,24 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16930
17039
|
if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? DEFAULT_FRAMEWORK) === "claude-code") {
|
|
16931
17040
|
try {
|
|
16932
17041
|
const agentProvisionDir = agentDir;
|
|
16933
|
-
const projectDir =
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
const provisionMcpPath =
|
|
16937
|
-
const projectMcpPath =
|
|
17042
|
+
const projectDir = join41(homedir17(), ".augmented", agent.code_name, "project");
|
|
17043
|
+
mkdirSync14(agentProvisionDir, { recursive: true });
|
|
17044
|
+
mkdirSync14(projectDir, { recursive: true });
|
|
17045
|
+
const provisionMcpPath = join41(agentProvisionDir, ".mcp.json");
|
|
17046
|
+
const projectMcpPath = join41(projectDir, ".mcp.json");
|
|
16938
17047
|
let mcpConfig = { mcpServers: {} };
|
|
16939
17048
|
try {
|
|
16940
|
-
mcpConfig = JSON.parse(
|
|
17049
|
+
mcpConfig = JSON.parse(readFileSync32(provisionMcpPath, "utf-8"));
|
|
16941
17050
|
if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
|
|
16942
17051
|
} catch {
|
|
16943
17052
|
}
|
|
16944
|
-
const localDirectChatChannel =
|
|
17053
|
+
const localDirectChatChannel = join41(homedir17(), ".augmented", "_mcp", "direct-chat-channel.js");
|
|
16945
17054
|
const directChatTeamSettings = refreshData.team?.settings;
|
|
16946
17055
|
const directChatTz = (() => {
|
|
16947
17056
|
const tz = directChatTeamSettings?.["timezone"];
|
|
16948
17057
|
return typeof tz === "string" && tz.trim() !== "" ? tz.trim() : void 0;
|
|
16949
17058
|
})();
|
|
16950
|
-
if (
|
|
17059
|
+
if (existsSync19(localDirectChatChannel)) {
|
|
16951
17060
|
const directChatEnv = {
|
|
16952
17061
|
AGT_HOST: requireHost(),
|
|
16953
17062
|
// ENG-5901 Track D: templated — the manager exports the real
|
|
@@ -16967,7 +17076,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16967
17076
|
// ~/.augmented/<codeName>/.current-turn-initiator.json. Note getAgentDir
|
|
16968
17077
|
// returns the agent root (NOT the /provision subdir `agentDir` points at),
|
|
16969
17078
|
// so it byte-matches the broker readers' path.
|
|
16970
|
-
AGT_TURN_INITIATOR_FILE:
|
|
17079
|
+
AGT_TURN_INITIATOR_FILE: join41(
|
|
16971
17080
|
frameworkAdapter.getAgentDir(agent.code_name),
|
|
16972
17081
|
".current-turn-initiator.json"
|
|
16973
17082
|
)
|
|
@@ -16987,10 +17096,10 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
16987
17096
|
log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
|
|
16988
17097
|
}
|
|
16989
17098
|
}
|
|
16990
|
-
const staleChannelsPath =
|
|
16991
|
-
if (
|
|
17099
|
+
const staleChannelsPath = join41(projectDir, ".mcp-channels.json");
|
|
17100
|
+
if (existsSync19(staleChannelsPath)) {
|
|
16992
17101
|
try {
|
|
16993
|
-
|
|
17102
|
+
rmSync8(staleChannelsPath, { force: true });
|
|
16994
17103
|
} catch {
|
|
16995
17104
|
}
|
|
16996
17105
|
}
|
|
@@ -17082,7 +17191,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17082
17191
|
}
|
|
17083
17192
|
if (hostFlagStore().getBoolean("connectivity-probe")) {
|
|
17084
17193
|
try {
|
|
17085
|
-
const probeProjectDir =
|
|
17194
|
+
const probeProjectDir = join41(homedir17(), ".augmented", agent.code_name, "project");
|
|
17086
17195
|
let probeSet = integrations;
|
|
17087
17196
|
try {
|
|
17088
17197
|
const quarantined = await api.post("/host/agent-integrations/quarantined", { agent_id: agent.agent_id });
|
|
@@ -17128,7 +17237,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17128
17237
|
const forceDue = attemptsLeft > 0;
|
|
17129
17238
|
let probeRan = false;
|
|
17130
17239
|
try {
|
|
17131
|
-
const probeProjectDir =
|
|
17240
|
+
const probeProjectDir = join41(homedir17(), ".augmented", agent.code_name, "project");
|
|
17132
17241
|
probeRan = await runAgentSessionToolBindProbes(agent, integrations, probeProjectDir, { forceDue });
|
|
17133
17242
|
} catch (err) {
|
|
17134
17243
|
log(`Session-tool-bind probe failed for '${agent.code_name}': ${err.message}`);
|
|
@@ -17205,11 +17314,11 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17205
17314
|
const intHash = computeIntegrationsHash(integrations);
|
|
17206
17315
|
const prevIntHash = agentState.knownIntegrationHashes.get(agent.agent_id);
|
|
17207
17316
|
if (intHash !== prevIntHash) {
|
|
17208
|
-
const projectDir =
|
|
17209
|
-
const envIntPath =
|
|
17317
|
+
const projectDir = join41(homedir17(), ".augmented", agent.code_name, "project");
|
|
17318
|
+
const envIntPath = join41(projectDir, ".env.integrations");
|
|
17210
17319
|
let preWriteEnv;
|
|
17211
17320
|
try {
|
|
17212
|
-
preWriteEnv =
|
|
17321
|
+
preWriteEnv = readFileSync32(envIntPath, "utf-8");
|
|
17213
17322
|
} catch {
|
|
17214
17323
|
preWriteEnv = void 0;
|
|
17215
17324
|
}
|
|
@@ -17228,9 +17337,9 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17228
17337
|
}
|
|
17229
17338
|
if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
|
|
17230
17339
|
try {
|
|
17231
|
-
const projectMcpPath =
|
|
17232
|
-
const postWriteEnv =
|
|
17233
|
-
const mcpContent =
|
|
17340
|
+
const projectMcpPath = join41(projectDir, ".mcp.json");
|
|
17341
|
+
const postWriteEnv = readFileSync32(envIntPath, "utf-8");
|
|
17342
|
+
const mcpContent = readFileSync32(projectMcpPath, "utf-8");
|
|
17234
17343
|
const changedVars = diffEnvIntegrations(preWriteEnv, postWriteEnv);
|
|
17235
17344
|
const mcpJsonForReap = JSON.parse(mcpContent);
|
|
17236
17345
|
const affectedServerKeys = findMcpServersUsingVars(mcpJsonForReap, changedVars);
|
|
@@ -17320,10 +17429,10 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17320
17429
|
desiredEntries.push({ serverId, url, headers: mcpHeaders, name: tk.toolkit_name });
|
|
17321
17430
|
}
|
|
17322
17431
|
const hashBasis = desiredEntries.slice().sort((a, b) => a.serverId.localeCompare(b.serverId)).map((e) => {
|
|
17323
|
-
const headersHash =
|
|
17432
|
+
const headersHash = createHash20("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
|
|
17324
17433
|
return `${e.serverId}|${e.url}|${headersHash}`;
|
|
17325
17434
|
}).join("\n");
|
|
17326
|
-
const mcpHash =
|
|
17435
|
+
const mcpHash = createHash20("sha256").update(hashBasis).digest("hex").slice(0, 16);
|
|
17327
17436
|
const prevMcpHash = agentState.knownManagedMcpHashes.get(agent.agent_id);
|
|
17328
17437
|
const structureHash = managedMcpStructureHash(desiredEntries);
|
|
17329
17438
|
const prevStructureHash = agentState.knownManagedMcpStructure.get(agent.agent_id);
|
|
@@ -17338,7 +17447,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17338
17447
|
if (mcpHash !== prevMcpHash) {
|
|
17339
17448
|
for (const e of desiredEntries) {
|
|
17340
17449
|
frameworkAdapter.writeMcpServer(agent.code_name, e.serverId, { url: e.url, headers: e.headers });
|
|
17341
|
-
const urlHash =
|
|
17450
|
+
const urlHash = createHash20("sha256").update(e.url).digest("hex").slice(0, 12);
|
|
17342
17451
|
log(`[managed-toolkit] ${agent.code_name}: wrote '${e.name}' (serverId=${e.serverId}, url_hash=${urlHash})`);
|
|
17343
17452
|
}
|
|
17344
17453
|
if (frameworkAdapter.removeMcpServer && frameworkAdapter.readMcpServers) {
|
|
@@ -17447,7 +17556,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17447
17556
|
if (frameworkAdapter.installSkillFiles) {
|
|
17448
17557
|
const currentIntegrationSkillIds = /* @__PURE__ */ new Set();
|
|
17449
17558
|
const installedIntegrationSkills = [];
|
|
17450
|
-
const { createHash:
|
|
17559
|
+
const { createHash: createHash21 } = await import("crypto");
|
|
17451
17560
|
const refreshAny = refreshData;
|
|
17452
17561
|
const contexts = refreshAny.integration_contexts ?? refreshAny.plugin_contexts ?? [];
|
|
17453
17562
|
const contextBySlug = /* @__PURE__ */ new Map();
|
|
@@ -17484,7 +17593,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17484
17593
|
)
|
|
17485
17594
|
}));
|
|
17486
17595
|
const bundle = buildIntegrationBundle(renderedScopes);
|
|
17487
|
-
const contentHash =
|
|
17596
|
+
const contentHash = createHash21("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
|
|
17488
17597
|
if (!shouldWriteIntegrationSkill(
|
|
17489
17598
|
agentState.knownSkillHashes,
|
|
17490
17599
|
agent.agent_id,
|
|
@@ -17507,23 +17616,23 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17507
17616
|
}
|
|
17508
17617
|
}
|
|
17509
17618
|
try {
|
|
17510
|
-
const { readdirSync:
|
|
17619
|
+
const { readdirSync: readdirSync13, rmSync: rmSync9 } = await import("fs");
|
|
17511
17620
|
const { homedir: homedir18 } = await import("os");
|
|
17512
17621
|
const frameworkId2 = frameworkAdapter.id;
|
|
17513
17622
|
const candidateSkillDirs = [
|
|
17514
17623
|
// Claude Code — framework runtime tree
|
|
17515
|
-
|
|
17624
|
+
join41(homedir18(), ".augmented", agent.code_name, "skills"),
|
|
17516
17625
|
// Claude Code — project tree
|
|
17517
|
-
|
|
17626
|
+
join41(homedir18(), ".augmented", agent.code_name, "project", ".claude", "skills"),
|
|
17518
17627
|
// Defensive: legacy provision-side path, not currently an
|
|
17519
17628
|
// install target but cheap to sweep.
|
|
17520
|
-
|
|
17629
|
+
join41(agentDir, ".claude", "skills")
|
|
17521
17630
|
];
|
|
17522
|
-
const existingDirs = candidateSkillDirs.filter((d) =>
|
|
17631
|
+
const existingDirs = candidateSkillDirs.filter((d) => existsSync19(d));
|
|
17523
17632
|
const discoveredEntries = /* @__PURE__ */ new Set();
|
|
17524
17633
|
for (const dir of existingDirs) {
|
|
17525
17634
|
try {
|
|
17526
|
-
for (const entry of
|
|
17635
|
+
for (const entry of readdirSync13(dir)) {
|
|
17527
17636
|
if (entry.startsWith("plugin-") || entry.startsWith("integration-")) {
|
|
17528
17637
|
discoveredEntries.add(entry);
|
|
17529
17638
|
}
|
|
@@ -17538,8 +17647,8 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17538
17647
|
entry,
|
|
17539
17648
|
dirs: existingDirs,
|
|
17540
17649
|
removeDir: (p) => {
|
|
17541
|
-
if (
|
|
17542
|
-
|
|
17650
|
+
if (existsSync19(p)) {
|
|
17651
|
+
rmSync9(p, { recursive: true, force: true });
|
|
17543
17652
|
}
|
|
17544
17653
|
}
|
|
17545
17654
|
});
|
|
@@ -17560,7 +17669,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17560
17669
|
const sharedSkillsPayload = refreshAny.shared_skills;
|
|
17561
17670
|
const desiredResolved = globalSkillsPayload !== void 0 || sharedSkillsPayload !== void 0;
|
|
17562
17671
|
const manifestPath = managedSkillManifestPath(
|
|
17563
|
-
|
|
17672
|
+
join41(homedir17(), ".augmented", agent.code_name)
|
|
17564
17673
|
);
|
|
17565
17674
|
const prevIds = /* @__PURE__ */ new Set([
|
|
17566
17675
|
...agentState.knownGlobalSkillIds.get(agent.agent_id) ?? /* @__PURE__ */ new Set(),
|
|
@@ -17569,7 +17678,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17569
17678
|
const plan = planGlobalSkillSync(
|
|
17570
17679
|
[...globalSkillsPayload ?? [], ...sharedSkillsPayload ?? []],
|
|
17571
17680
|
prevIds,
|
|
17572
|
-
(content) =>
|
|
17681
|
+
(content) => createHash21("sha256").update(content).digest("hex").slice(0, 12),
|
|
17573
17682
|
(skillId) => agentState.knownSkillHashes.get(`global-skill:${agent.agent_id}:${skillId}`),
|
|
17574
17683
|
{ desiredResolved }
|
|
17575
17684
|
);
|
|
@@ -17580,16 +17689,16 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17580
17689
|
}
|
|
17581
17690
|
if (plan.removes.length) {
|
|
17582
17691
|
const globalSkillDirs = [
|
|
17583
|
-
|
|
17584
|
-
|
|
17585
|
-
|
|
17692
|
+
join41(homedir17(), ".augmented", agent.code_name, "skills"),
|
|
17693
|
+
join41(homedir17(), ".augmented", agent.code_name, "project", ".claude", "skills"),
|
|
17694
|
+
join41(agentDir, ".claude", "skills")
|
|
17586
17695
|
];
|
|
17587
17696
|
for (const id of plan.removes) {
|
|
17588
17697
|
let prunedAny = false;
|
|
17589
17698
|
for (const dir of globalSkillDirs) {
|
|
17590
|
-
const p =
|
|
17591
|
-
if (
|
|
17592
|
-
|
|
17699
|
+
const p = join41(dir, id);
|
|
17700
|
+
if (existsSync19(p) && existsSync19(join41(p, "SKILL.md"))) {
|
|
17701
|
+
rmSync8(p, { recursive: true, force: true });
|
|
17593
17702
|
prunedAny = true;
|
|
17594
17703
|
}
|
|
17595
17704
|
}
|
|
@@ -17620,7 +17729,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17620
17729
|
const slug = hook.integration_slug ?? hook.plugin_slug;
|
|
17621
17730
|
if (!slug) continue;
|
|
17622
17731
|
try {
|
|
17623
|
-
const scriptHash =
|
|
17732
|
+
const scriptHash = createHash21("sha256").update(hook.script).digest("hex").slice(0, 12);
|
|
17624
17733
|
const hookKey = `${agent.agent_id}:${frameworkAdapter.id}:plugin-hook:${slug}:on_install`;
|
|
17625
17734
|
if (agentState.knownSkillHashes.get(hookKey) === scriptHash) continue;
|
|
17626
17735
|
const result = await frameworkAdapter.executePluginHook({
|
|
@@ -17635,9 +17744,9 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17635
17744
|
} else if (result.timedOut) {
|
|
17636
17745
|
log(`Integration hook on_install '${slug}' TIMED OUT for '${agent.code_name}' after ${result.durationMs}ms`);
|
|
17637
17746
|
} else {
|
|
17638
|
-
const stderrHash =
|
|
17747
|
+
const stderrHash = createHash21("sha256").update(result.stderr).digest("hex").slice(0, 12);
|
|
17639
17748
|
const missingCmd = result.exitCode === 127 ? extractCommandNotFound(result.stderr) : null;
|
|
17640
|
-
const missingCmdHash = missingCmd ?
|
|
17749
|
+
const missingCmdHash = missingCmd ? createHash21("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
|
|
17641
17750
|
log(
|
|
17642
17751
|
`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}]`
|
|
17643
17752
|
);
|
|
@@ -17844,8 +17953,8 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
17844
17953
|
const sess = getSessionState(agent.code_name);
|
|
17845
17954
|
let mcpJsonParsed = null;
|
|
17846
17955
|
try {
|
|
17847
|
-
const mcpPath =
|
|
17848
|
-
mcpJsonParsed = JSON.parse(
|
|
17956
|
+
const mcpPath = join41(getProjectDir(agent.code_name), ".mcp.json");
|
|
17957
|
+
mcpJsonParsed = JSON.parse(readFileSync32(mcpPath, "utf-8"));
|
|
17849
17958
|
} catch {
|
|
17850
17959
|
}
|
|
17851
17960
|
reapMissingMcpSessions({
|
|
@@ -18227,7 +18336,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
18227
18336
|
freshDoneIds.add(item.id);
|
|
18228
18337
|
}
|
|
18229
18338
|
} catch (err) {
|
|
18230
|
-
const errId =
|
|
18339
|
+
const errId = createHash20("sha256").update(err instanceof Error ? err.message : String(err)).digest("hex").slice(0, 12);
|
|
18231
18340
|
log(`Reap API error for item_id=${item.id} error_id=${errId}`);
|
|
18232
18341
|
}
|
|
18233
18342
|
if (reapAction === "dead_letter") {
|
|
@@ -18275,10 +18384,10 @@ Retried to the limit after repeated stalls \u2014 needs a look.`).catch(() => {
|
|
|
18275
18384
|
}
|
|
18276
18385
|
}
|
|
18277
18386
|
const trackedFiles = frameworkAdapter.driftTrackedFiles();
|
|
18278
|
-
if (trackedFiles.length > 0 &&
|
|
18387
|
+
if (trackedFiles.length > 0 && existsSync19(agentDir)) {
|
|
18279
18388
|
const hashes = /* @__PURE__ */ new Map();
|
|
18280
18389
|
for (const file of trackedFiles) {
|
|
18281
|
-
const h = hashFile(
|
|
18390
|
+
const h = hashFile(join41(agentDir, file));
|
|
18282
18391
|
if (h) hashes.set(file, h);
|
|
18283
18392
|
}
|
|
18284
18393
|
agentState.writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -18293,7 +18402,7 @@ Retried to the limit after repeated stalls \u2014 needs a look.`).catch(() => {
|
|
|
18293
18402
|
refreshData.agent.onboarding_state
|
|
18294
18403
|
);
|
|
18295
18404
|
const obStep = obState.step;
|
|
18296
|
-
const markerPath =
|
|
18405
|
+
const markerPath = join41(homedir17(), ".augmented", agent.code_name, "onboarding-drive.json");
|
|
18297
18406
|
const marker = readOnboardingDriveMarker(markerPath);
|
|
18298
18407
|
const obContactRaw = refreshData.agent.manager_last_contacted_at;
|
|
18299
18408
|
const obContact = typeof obContactRaw === "string" && obContactRaw ? obContactRaw : null;
|
|
@@ -18396,7 +18505,7 @@ async function ensureOpencodeRuntime(agent, refreshData, agentTimezone) {
|
|
|
18396
18505
|
}
|
|
18397
18506
|
stopOpencodeSlackIngest(codeName, log);
|
|
18398
18507
|
stopOpencodeTelegramIngest(codeName, log);
|
|
18399
|
-
const opencodeProjectDir =
|
|
18508
|
+
const opencodeProjectDir = join41(getFramework("opencode").getAgentDir(codeName), "provision");
|
|
18400
18509
|
const serveEnv = {
|
|
18401
18510
|
AGT_HOST: requireHost(),
|
|
18402
18511
|
AGT_API_KEY: getApiKey() ?? void 0,
|
|
@@ -18451,8 +18560,8 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
18451
18560
|
});
|
|
18452
18561
|
}
|
|
18453
18562
|
const projectDir = getProjectDir(codeName);
|
|
18454
|
-
const mcpConfigPath =
|
|
18455
|
-
const claudeMdPath =
|
|
18563
|
+
const mcpConfigPath = join41(projectDir, ".mcp.json");
|
|
18564
|
+
const claudeMdPath = join41(projectDir, "CLAUDE.md");
|
|
18456
18565
|
if (restartBreaker.isTripped(codeName)) {
|
|
18457
18566
|
const trip = restartBreaker.getTrip(codeName);
|
|
18458
18567
|
return {
|
|
@@ -18710,7 +18819,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
18710
18819
|
const ctx = getLastFailureContext(codeName);
|
|
18711
18820
|
const recovery = prepareForRespawn(codeName);
|
|
18712
18821
|
const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
|
|
18713
|
-
${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${
|
|
18822
|
+
${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash20("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
|
|
18714
18823
|
const sigSummary = ctx.signature !== "unknown" ? `; signature=${ctx.signature}` : "";
|
|
18715
18824
|
const recoverySummary = recovery ? `; recovery=${recovery}` : "";
|
|
18716
18825
|
log(
|
|
@@ -18724,7 +18833,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash19("sha256")
|
|
|
18724
18833
|
);
|
|
18725
18834
|
getHostId().then((hostId) => {
|
|
18726
18835
|
if (!hostId) return;
|
|
18727
|
-
const paneTailHash = zombie.paneTail ? `sha256:${
|
|
18836
|
+
const paneTailHash = zombie.paneTail ? `sha256:${createHash20("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
|
|
18728
18837
|
return api.post("/host/events", {
|
|
18729
18838
|
host_id: hostId,
|
|
18730
18839
|
agent_code_name: codeName,
|
|
@@ -18934,7 +19043,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash19("sha256")
|
|
|
18934
19043
|
if (!claudeAuthTupleBySession.has(codeName)) {
|
|
18935
19044
|
claudeAuthTupleBySession.set(codeName, currentAuthTuple);
|
|
18936
19045
|
}
|
|
18937
|
-
const stableTasksHash =
|
|
19046
|
+
const stableTasksHash = createHash20("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
|
|
18938
19047
|
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
18939
19048
|
if (stableTasksHash !== prevHash) {
|
|
18940
19049
|
const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
|
|
@@ -19412,7 +19521,7 @@ function ensureRealtimeKanbanStarted(agentStates) {
|
|
|
19412
19521
|
);
|
|
19413
19522
|
}
|
|
19414
19523
|
}).catch((err) => {
|
|
19415
|
-
const errId =
|
|
19524
|
+
const errId = createHash20("sha256").update(err instanceof Error ? err.message : String(err)).digest("hex").slice(0, 12);
|
|
19416
19525
|
log(
|
|
19417
19526
|
`[realtime] Work trigger enqueue threw for '${agent.codeName}' item_id=${item.id} error_id=${errId} \u2014 hybrid nudge will retry`
|
|
19418
19527
|
);
|
|
@@ -19703,8 +19812,8 @@ async function processDirectChatMessage(agent, msg) {
|
|
|
19703
19812
|
if (useDoorbell) {
|
|
19704
19813
|
try {
|
|
19705
19814
|
const doorbell = directChatDoorbellPath(agent.agentId, homedir17());
|
|
19706
|
-
|
|
19707
|
-
|
|
19815
|
+
mkdirSync14(dirname10(doorbell), { recursive: true });
|
|
19816
|
+
writeFileSync18(doorbell, String(Date.now()));
|
|
19708
19817
|
log(`[direct-chat] Doorbell rung for '${agent.codeName}' (msg=${msg.id}) \u2014 in-session MCP will pull via the cursor`);
|
|
19709
19818
|
return;
|
|
19710
19819
|
} catch (err) {
|
|
@@ -19832,8 +19941,8 @@ ${formatRunMarker(run_id)}` : KANBAN_CHECK_COMMAND;
|
|
|
19832
19941
|
if (run_id) openInjectedRunByCode.set(codeName, run_id);
|
|
19833
19942
|
try {
|
|
19834
19943
|
const doorbell = directChatDoorbellPath(agentId, homedir17());
|
|
19835
|
-
|
|
19836
|
-
|
|
19944
|
+
mkdirSync14(dirname10(doorbell), { recursive: true });
|
|
19945
|
+
writeFileSync18(doorbell, String(Date.now()));
|
|
19837
19946
|
} catch (err) {
|
|
19838
19947
|
log(`[kanban] doorbell ring failed for '${codeName}': ${err.message} (notice still queued)`);
|
|
19839
19948
|
}
|
|
@@ -20164,17 +20273,17 @@ var lastLocalFileHash = /* @__PURE__ */ new Map();
|
|
|
20164
20273
|
var lastMemoriesBody = /* @__PURE__ */ new Map();
|
|
20165
20274
|
var memoryManifests = /* @__PURE__ */ new Map();
|
|
20166
20275
|
function memoryRetirementDir(configDir, codeName) {
|
|
20167
|
-
return
|
|
20276
|
+
return join41(configDir, "_memory-retirement", codeName);
|
|
20168
20277
|
}
|
|
20169
20278
|
function memoryManifestPath(configDir, codeName) {
|
|
20170
|
-
return
|
|
20279
|
+
return join41(memoryRetirementDir(configDir, codeName), "manifest.json");
|
|
20171
20280
|
}
|
|
20172
20281
|
function loadMemoryManifest(agentId, configDir, codeName) {
|
|
20173
20282
|
const cached = memoryManifests.get(agentId);
|
|
20174
20283
|
if (cached) return cached;
|
|
20175
20284
|
let manifest = {};
|
|
20176
20285
|
try {
|
|
20177
|
-
const raw =
|
|
20286
|
+
const raw = readFileSync32(memoryManifestPath(configDir, codeName), "utf-8");
|
|
20178
20287
|
const parsed = JSON.parse(raw);
|
|
20179
20288
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
20180
20289
|
for (const [name, entry] of Object.entries(parsed)) {
|
|
@@ -20194,15 +20303,15 @@ function saveMemoryManifest(agentId, configDir, codeName) {
|
|
|
20194
20303
|
if (!manifest) return;
|
|
20195
20304
|
try {
|
|
20196
20305
|
const path = memoryManifestPath(configDir, codeName);
|
|
20197
|
-
|
|
20306
|
+
mkdirSync14(memoryRetirementDir(configDir, codeName), { recursive: true });
|
|
20198
20307
|
const tmp = `${path}.tmp`;
|
|
20199
|
-
|
|
20200
|
-
|
|
20308
|
+
writeFileSync18(tmp, JSON.stringify(manifest, null, 2));
|
|
20309
|
+
renameSync11(tmp, path);
|
|
20201
20310
|
} catch {
|
|
20202
20311
|
}
|
|
20203
20312
|
}
|
|
20204
20313
|
function retiredMemoryDir(configDir, codeName) {
|
|
20205
|
-
return
|
|
20314
|
+
return join41(memoryRetirementDir(configDir, codeName), "retired");
|
|
20206
20315
|
}
|
|
20207
20316
|
var RETIRED_MEMORY_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
20208
20317
|
var lastRetirementReport = /* @__PURE__ */ new Map();
|
|
@@ -20281,15 +20390,15 @@ function applyMemoryTombstones(opts) {
|
|
|
20281
20390
|
log2(`[memory-retire] ${agent.code_name}: KEPT '${tomb.name}' \u2014 no write record, not ours to remove`);
|
|
20282
20391
|
continue;
|
|
20283
20392
|
}
|
|
20284
|
-
const filePath =
|
|
20285
|
-
if (!
|
|
20393
|
+
const filePath = join41(memoryDir, entry.file);
|
|
20394
|
+
if (!existsSync19(filePath)) {
|
|
20286
20395
|
outcomes.already_gone++;
|
|
20287
20396
|
delete manifest[tomb.name];
|
|
20288
20397
|
manifestDirty = true;
|
|
20289
20398
|
continue;
|
|
20290
20399
|
}
|
|
20291
20400
|
try {
|
|
20292
|
-
const actual =
|
|
20401
|
+
const actual = createHash20("sha256").update(readFileSync32(filePath)).digest("hex");
|
|
20293
20402
|
if (actual !== entry.sha) {
|
|
20294
20403
|
outcomes.kept_modified++;
|
|
20295
20404
|
outcomes.unapplied.push({ name: tomb.name, reason: "kept_modified" });
|
|
@@ -20299,16 +20408,16 @@ function applyMemoryTombstones(opts) {
|
|
|
20299
20408
|
continue;
|
|
20300
20409
|
}
|
|
20301
20410
|
const destDir = retiredMemoryDir(configDir, agent.code_name);
|
|
20302
|
-
|
|
20411
|
+
mkdirSync14(destDir, { recursive: true });
|
|
20303
20412
|
const stamp = Date.now();
|
|
20304
|
-
let dest =
|
|
20305
|
-
for (let n = 1;
|
|
20306
|
-
dest =
|
|
20413
|
+
let dest = join41(destDir, `${entry.file}.${stamp}.retired`);
|
|
20414
|
+
for (let n = 1; existsSync19(dest); n++) {
|
|
20415
|
+
dest = join41(destDir, `${entry.file}.${stamp}-${n}.retired`);
|
|
20307
20416
|
}
|
|
20308
|
-
|
|
20417
|
+
renameSync11(filePath, dest);
|
|
20309
20418
|
try {
|
|
20310
20419
|
const now = Date.now() / 1e3;
|
|
20311
|
-
|
|
20420
|
+
utimesSync4(dest, now, now);
|
|
20312
20421
|
} catch {
|
|
20313
20422
|
}
|
|
20314
20423
|
delete manifest[tomb.name];
|
|
@@ -20336,15 +20445,15 @@ function applyMemoryTombstones(opts) {
|
|
|
20336
20445
|
}
|
|
20337
20446
|
function reapRetiredMemories(configDir, codeName, log2) {
|
|
20338
20447
|
const dir = retiredMemoryDir(configDir, codeName);
|
|
20339
|
-
if (!
|
|
20448
|
+
if (!existsSync19(dir)) return;
|
|
20340
20449
|
const cutoff = Date.now() - RETIRED_MEMORY_TTL_MS;
|
|
20341
20450
|
let reaped = 0;
|
|
20342
20451
|
try {
|
|
20343
|
-
for (const file of
|
|
20452
|
+
for (const file of readdirSync12(dir)) {
|
|
20344
20453
|
if (!file.endsWith(".retired")) continue;
|
|
20345
|
-
const path =
|
|
20454
|
+
const path = join41(dir, file);
|
|
20346
20455
|
try {
|
|
20347
|
-
if (
|
|
20456
|
+
if (statSync11(path).mtimeMs < cutoff) {
|
|
20348
20457
|
unlinkSync6(path);
|
|
20349
20458
|
reaped++;
|
|
20350
20459
|
}
|
|
@@ -20357,8 +20466,8 @@ function reapRetiredMemories(configDir, codeName, log2) {
|
|
|
20357
20466
|
if (reaped > 0) log2(`[memory-retire] ${codeName}: reaped ${reaped} retired memory file(s) past TTL`);
|
|
20358
20467
|
}
|
|
20359
20468
|
async function syncMemories(agent, configDir, log2) {
|
|
20360
|
-
const projectDir =
|
|
20361
|
-
const memoryDir =
|
|
20469
|
+
const projectDir = join41(configDir, agent.code_name, "project");
|
|
20470
|
+
const memoryDir = join41(projectDir, "memory");
|
|
20362
20471
|
const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
|
|
20363
20472
|
if (isFreshSync) {
|
|
20364
20473
|
log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
|
|
@@ -20382,15 +20491,15 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
20382
20491
|
}
|
|
20383
20492
|
pendingFreshMemorySync.delete(agent.agent_id);
|
|
20384
20493
|
}
|
|
20385
|
-
if (
|
|
20494
|
+
if (existsSync19(memoryDir)) {
|
|
20386
20495
|
const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
|
|
20387
20496
|
const currentHashes = /* @__PURE__ */ new Map();
|
|
20388
20497
|
const changedMemories = [];
|
|
20389
|
-
for (const file of
|
|
20498
|
+
for (const file of readdirSync12(memoryDir)) {
|
|
20390
20499
|
if (!file.endsWith(".md")) continue;
|
|
20391
20500
|
try {
|
|
20392
|
-
const raw =
|
|
20393
|
-
const fileHash =
|
|
20501
|
+
const raw = readFileSync32(join41(memoryDir, file), "utf-8");
|
|
20502
|
+
const fileHash = createHash20("sha256").update(raw).digest("hex").slice(0, 16);
|
|
20394
20503
|
currentHashes.set(file, fileHash);
|
|
20395
20504
|
if (prevHashes.get(file) === fileHash) continue;
|
|
20396
20505
|
const parsed = parseMemoryFile(raw, file.replace(/\.md$/, ""));
|
|
@@ -20414,7 +20523,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
20414
20523
|
} catch (err) {
|
|
20415
20524
|
for (const mem of changedMemories) {
|
|
20416
20525
|
for (const [file] of currentHashes) {
|
|
20417
|
-
const parsed = parseMemoryFile(
|
|
20526
|
+
const parsed = parseMemoryFile(readFileSync32(join41(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
|
|
20418
20527
|
if (parsed?.name === mem.name) currentHashes.delete(file);
|
|
20419
20528
|
}
|
|
20420
20529
|
}
|
|
@@ -20440,8 +20549,8 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
20440
20549
|
}
|
|
20441
20550
|
}
|
|
20442
20551
|
async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
|
|
20443
|
-
const localFiles =
|
|
20444
|
-
const localListHash =
|
|
20552
|
+
const localFiles = existsSync19(memoryDir) ? readdirSync12(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
|
|
20553
|
+
const localListHash = createHash20("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
|
|
20445
20554
|
const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
|
|
20446
20555
|
const prevDownload = lastDownloadHash.get(agent.agent_id);
|
|
20447
20556
|
const memoriesToken = memoriesFetchGate.beginFetch(agent.agent_id);
|
|
@@ -20452,6 +20561,10 @@ async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
|
|
|
20452
20561
|
const quoted = lastMemoriesBody.get(agent.agent_id);
|
|
20453
20562
|
let wire = await api.post("/host/memories", {
|
|
20454
20563
|
agent_id: agent.agent_id,
|
|
20564
|
+
memories_manifest: true,
|
|
20565
|
+
// ENG-9698 renamed this field from `known_hash`. Emitting the NEW name
|
|
20566
|
+
// only: the route reads `known_token ?? known_hash`, so a new host against
|
|
20567
|
+
// an old API degrades to a full response rather than breaking.
|
|
20455
20568
|
...quoted ? { known_token: quoted.hash } : {}
|
|
20456
20569
|
});
|
|
20457
20570
|
memoriesFetchGate.markFetched(agent.agent_id, memoriesToken);
|
|
@@ -20460,7 +20573,10 @@ async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
|
|
|
20460
20573
|
log2(
|
|
20461
20574
|
`Memory download for '${agent.code_name}': unchanged marker with no cached body (cache purged mid-flight?) \u2014 re-fetching in full`
|
|
20462
20575
|
);
|
|
20463
|
-
wire = await api.post("/host/memories", {
|
|
20576
|
+
wire = await api.post("/host/memories", {
|
|
20577
|
+
agent_id: agent.agent_id,
|
|
20578
|
+
memories_manifest: true
|
|
20579
|
+
});
|
|
20464
20580
|
held = void 0;
|
|
20465
20581
|
}
|
|
20466
20582
|
let dbMemories;
|
|
@@ -20481,23 +20597,52 @@ async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
|
|
|
20481
20597
|
pollCycleMemoriesFull += 1;
|
|
20482
20598
|
}
|
|
20483
20599
|
const tombstones = Array.isArray(dbMemories.tombstones) ? dbMemories.tombstones : null;
|
|
20484
|
-
|
|
20600
|
+
let memories = dbMemories.memories;
|
|
20601
|
+
if (dbMemories.memories_manifest) {
|
|
20602
|
+
const resolved = await resolveMemoriesFromManifest({
|
|
20603
|
+
manifest: dbMemories.memories_manifest,
|
|
20604
|
+
// Per-agent, not host-wide: memories are agent-private, so a shared
|
|
20605
|
+
// store would buy almost no dedupe while exposing one agent's content
|
|
20606
|
+
// to every other agent on the host. See memory-cache.ts's header.
|
|
20607
|
+
cacheDir: join41(configDir, agent.code_name, "_memory_bodies"),
|
|
20608
|
+
fetchContents: async (hashes) => {
|
|
20609
|
+
const res = await api.post(
|
|
20610
|
+
"/host/memories/contents",
|
|
20611
|
+
{ agent_id: agent.agent_id, hashes }
|
|
20612
|
+
);
|
|
20613
|
+
return res.contents ?? [];
|
|
20614
|
+
},
|
|
20615
|
+
log: log2
|
|
20616
|
+
});
|
|
20617
|
+
memories = resolved.memories;
|
|
20618
|
+
if (dbMemories.memories_manifest_truncated) {
|
|
20619
|
+
log2(
|
|
20620
|
+
`[memory-cache] ${agent.code_name}: server returned a TRUNCATED manifest (${dbMemories.memories_manifest.length} entries, ceiling reached) \u2014 corpus is partial this tick`
|
|
20621
|
+
);
|
|
20622
|
+
}
|
|
20623
|
+
if (resolved.unresolved > 0) {
|
|
20624
|
+
log2(
|
|
20625
|
+
`[memory-cache] ${agent.code_name}: ${resolved.unresolved} of ${dbMemories.memories_manifest.length} memory bodies unresolved this tick`
|
|
20626
|
+
);
|
|
20627
|
+
}
|
|
20628
|
+
}
|
|
20629
|
+
const responseHash = createHash20("sha256").update(JSON.stringify({ m: memories ?? [], t: tombstones })).digest("hex").slice(0, 16);
|
|
20485
20630
|
if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
|
|
20486
20631
|
return { status: "skipped", tombstones, truncated: dbMemories.tombstones_truncated === true };
|
|
20487
20632
|
}
|
|
20488
20633
|
lastDownloadHash.set(agent.agent_id, responseHash);
|
|
20489
20634
|
lastLocalFileHash.set(agent.agent_id, localListHash);
|
|
20490
|
-
if (
|
|
20491
|
-
|
|
20635
|
+
if (memories?.length) {
|
|
20636
|
+
mkdirSync14(memoryDir, { recursive: true });
|
|
20492
20637
|
const manifest = loadMemoryManifest(agent.agent_id, configDir, agent.code_name);
|
|
20493
20638
|
let written = 0;
|
|
20494
20639
|
let overwritten = 0;
|
|
20495
|
-
for (let i = 0; i <
|
|
20496
|
-
const mem =
|
|
20640
|
+
for (let i = 0; i < memories.length; i++) {
|
|
20641
|
+
const mem = memories[i];
|
|
20497
20642
|
const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
|
|
20498
20643
|
const slug = rawSlug || `memory-${i}`;
|
|
20499
20644
|
const fileName = `${slug}.md`;
|
|
20500
|
-
const filePath =
|
|
20645
|
+
const filePath = join41(memoryDir, fileName);
|
|
20501
20646
|
const desired = `---
|
|
20502
20647
|
name: ${JSON.stringify(mem.name)}
|
|
20503
20648
|
type: ${mem.type}
|
|
@@ -20507,17 +20652,17 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
|
|
|
20507
20652
|
${mem.content}
|
|
20508
20653
|
`;
|
|
20509
20654
|
const record = () => {
|
|
20510
|
-
const sha =
|
|
20655
|
+
const sha = createHash20("sha256").update(desired).digest("hex");
|
|
20511
20656
|
const prev = manifest[mem.name];
|
|
20512
20657
|
if (prev?.file === fileName && prev.sha === sha) return false;
|
|
20513
20658
|
manifest[mem.name] = { file: fileName, sha };
|
|
20514
20659
|
return true;
|
|
20515
20660
|
};
|
|
20516
20661
|
let manifestDirty = false;
|
|
20517
|
-
if (
|
|
20662
|
+
if (existsSync19(filePath)) {
|
|
20518
20663
|
let existing = "";
|
|
20519
20664
|
try {
|
|
20520
|
-
existing =
|
|
20665
|
+
existing = readFileSync32(filePath, "utf-8");
|
|
20521
20666
|
} catch {
|
|
20522
20667
|
}
|
|
20523
20668
|
if (existing === desired) {
|
|
@@ -20525,18 +20670,18 @@ ${mem.content}
|
|
|
20525
20670
|
if (manifestDirty) saveMemoryManifest(agent.agent_id, configDir, agent.code_name);
|
|
20526
20671
|
continue;
|
|
20527
20672
|
}
|
|
20528
|
-
|
|
20673
|
+
writeFileSync18(filePath, desired);
|
|
20529
20674
|
overwritten++;
|
|
20530
20675
|
} else {
|
|
20531
|
-
|
|
20676
|
+
writeFileSync18(filePath, desired);
|
|
20532
20677
|
written++;
|
|
20533
20678
|
}
|
|
20534
20679
|
if (record()) manifestDirty = true;
|
|
20535
20680
|
if (manifestDirty) saveMemoryManifest(agent.agent_id, configDir, agent.code_name);
|
|
20536
20681
|
}
|
|
20537
20682
|
if (written > 0 || overwritten > 0) {
|
|
20538
|
-
const updatedFiles =
|
|
20539
|
-
lastLocalFileHash.set(agent.agent_id,
|
|
20683
|
+
const updatedFiles = readdirSync12(memoryDir).filter((f) => f.endsWith(".md")).sort();
|
|
20684
|
+
lastLocalFileHash.set(agent.agent_id, createHash20("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
|
|
20540
20685
|
log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
|
|
20541
20686
|
}
|
|
20542
20687
|
}
|
|
@@ -20547,9 +20692,9 @@ ${mem.content}
|
|
|
20547
20692
|
}
|
|
20548
20693
|
}
|
|
20549
20694
|
async function cleanupAgentFiles(codeName, agentDir) {
|
|
20550
|
-
if (
|
|
20695
|
+
if (existsSync19(agentDir)) {
|
|
20551
20696
|
try {
|
|
20552
|
-
|
|
20697
|
+
rmSync8(agentDir, { recursive: true, force: true });
|
|
20553
20698
|
log(`Removed provision directory for '${codeName}'`);
|
|
20554
20699
|
} catch (err) {
|
|
20555
20700
|
log(`Failed to remove provision dir for '${codeName}': ${err.message}`);
|
|
@@ -20817,8 +20962,8 @@ function startManager(opts) {
|
|
|
20817
20962
|
config = opts;
|
|
20818
20963
|
try {
|
|
20819
20964
|
const stateFile = getStateFile();
|
|
20820
|
-
if (
|
|
20821
|
-
const raw =
|
|
20965
|
+
if (existsSync19(stateFile)) {
|
|
20966
|
+
const raw = readFileSync32(stateFile, "utf-8");
|
|
20822
20967
|
const parsed = JSON.parse(raw);
|
|
20823
20968
|
if (Array.isArray(parsed.agents)) {
|
|
20824
20969
|
state8.agents = parsed.agents;
|
|
@@ -20845,7 +20990,7 @@ function startManager(opts) {
|
|
|
20845
20990
|
log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
|
|
20846
20991
|
}
|
|
20847
20992
|
log(
|
|
20848
|
-
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${
|
|
20993
|
+
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join41(homedir17(), ".augmented", "manager.log")}`
|
|
20849
20994
|
);
|
|
20850
20995
|
deployMcpAssets();
|
|
20851
20996
|
reapOrphanChannelMcps({ log });
|
|
@@ -20874,7 +21019,7 @@ async function reapOrphanedClaudePids() {
|
|
|
20874
21019
|
const looksLikeClaude = (pid) => {
|
|
20875
21020
|
if (process.platform !== "linux") return true;
|
|
20876
21021
|
try {
|
|
20877
|
-
const comm =
|
|
21022
|
+
const comm = readFileSync32(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
|
|
20878
21023
|
return comm.includes("claude");
|
|
20879
21024
|
} catch {
|
|
20880
21025
|
return false;
|
|
@@ -20971,14 +21116,14 @@ function restartRunningChannelMcps(basenames) {
|
|
|
20971
21116
|
}
|
|
20972
21117
|
}
|
|
20973
21118
|
function deployMcpAssets() {
|
|
20974
|
-
const targetDir =
|
|
20975
|
-
|
|
21119
|
+
const targetDir = join41(homedir17(), ".augmented", "_mcp");
|
|
21120
|
+
mkdirSync14(targetDir, { recursive: true });
|
|
20976
21121
|
const moduleDir = dirname10(fileURLToPath(import.meta.url));
|
|
20977
21122
|
let mcpSourceDir = "";
|
|
20978
21123
|
let dir = moduleDir;
|
|
20979
21124
|
for (let i = 0; i < 6; i++) {
|
|
20980
|
-
const candidate =
|
|
20981
|
-
if (
|
|
21125
|
+
const candidate = join41(dir, "dist", "mcp");
|
|
21126
|
+
if (existsSync19(join41(candidate, "index.js"))) {
|
|
20982
21127
|
mcpSourceDir = candidate;
|
|
20983
21128
|
break;
|
|
20984
21129
|
}
|
|
@@ -20995,8 +21140,8 @@ function deployMcpAssets() {
|
|
|
20995
21140
|
const failedFiles = [];
|
|
20996
21141
|
const fileHash = (p) => {
|
|
20997
21142
|
try {
|
|
20998
|
-
if (!
|
|
20999
|
-
return
|
|
21143
|
+
if (!existsSync19(p)) return null;
|
|
21144
|
+
return createHash20("sha256").update(readFileSync32(p)).digest("hex");
|
|
21000
21145
|
} catch {
|
|
21001
21146
|
return null;
|
|
21002
21147
|
}
|
|
@@ -21067,9 +21212,9 @@ function deployMcpAssets() {
|
|
|
21067
21212
|
// needs restarting to pick up a token rotation.
|
|
21068
21213
|
"xero.js"
|
|
21069
21214
|
]) {
|
|
21070
|
-
const src =
|
|
21071
|
-
const dst =
|
|
21072
|
-
if (!
|
|
21215
|
+
const src = join41(mcpSourceDir, file);
|
|
21216
|
+
const dst = join41(targetDir, file);
|
|
21217
|
+
if (!existsSync19(src)) continue;
|
|
21073
21218
|
attemptedFiles.push(file);
|
|
21074
21219
|
const before = fileHash(dst);
|
|
21075
21220
|
try {
|
|
@@ -21094,23 +21239,23 @@ function deployMcpAssets() {
|
|
|
21094
21239
|
log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
|
|
21095
21240
|
restartRunningChannelMcps(changedBasenames);
|
|
21096
21241
|
}
|
|
21097
|
-
const localMcpPath =
|
|
21242
|
+
const localMcpPath = join41(targetDir, "index.js");
|
|
21098
21243
|
try {
|
|
21099
|
-
const agentsDir =
|
|
21100
|
-
if (
|
|
21101
|
-
for (const entry of
|
|
21244
|
+
const agentsDir = join41(homedir17(), ".augmented", "agents");
|
|
21245
|
+
if (existsSync19(agentsDir)) {
|
|
21246
|
+
for (const entry of readdirSync12(agentsDir, { withFileTypes: true })) {
|
|
21102
21247
|
if (!entry.isDirectory()) continue;
|
|
21103
21248
|
for (const subdir of ["provision", "project"]) {
|
|
21104
|
-
const mcpJsonPath =
|
|
21249
|
+
const mcpJsonPath = join41(agentsDir, entry.name, subdir, ".mcp.json");
|
|
21105
21250
|
try {
|
|
21106
|
-
const raw =
|
|
21251
|
+
const raw = readFileSync32(mcpJsonPath, "utf-8");
|
|
21107
21252
|
if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
|
|
21108
21253
|
const mcpConfig = JSON.parse(raw);
|
|
21109
21254
|
const augServer = mcpConfig.mcpServers?.["augmented"];
|
|
21110
21255
|
if (!augServer) continue;
|
|
21111
21256
|
augServer.command = "node";
|
|
21112
21257
|
augServer.args = [localMcpPath];
|
|
21113
|
-
|
|
21258
|
+
writeFileSync18(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
|
|
21114
21259
|
log(`[manager] Patched ${entry.name}/${subdir}/.mcp.json: npx \u2192 node`);
|
|
21115
21260
|
} catch {
|
|
21116
21261
|
}
|