@integrity-labs/agt-cli 0.28.666 → 0.28.668
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.
- package/dist/bin/agt.js +5 -5
- package/dist/{chunk-FYZOD3SS.js → chunk-4GA4K2BF.js} +57 -1
- package/dist/chunk-4GA4K2BF.js.map +1 -0
- package/dist/{chunk-EX5XJEGF.js → chunk-52V5BMBC.js} +2 -2
- package/dist/{chunk-P7UIFZQO.js → chunk-EQK5Q7ZL.js} +4 -4
- package/dist/{claude-pair-runtime-XSUQMCIQ.js → claude-pair-runtime-SXEBKHYM.js} +2 -2
- package/dist/lib/manager-worker.js +234 -24
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/direct-chat-channel.js +56 -0
- package/dist/mcp/index.js +56 -0
- package/dist/mcp/origami.js +56 -0
- package/dist/mcp/slack-channel.js +56 -0
- package/dist/mcp/telegram-channel.js +56 -0
- package/dist/{persistent-session-SQWO4TKG.js → persistent-session-3OCFA42T.js} +3 -3
- package/dist/{responsiveness-probe-RWMERSER.js → responsiveness-probe-ZEKOULXD.js} +3 -3
- package/dist/{session-auth-dead-OOWR5BPI.js → session-auth-dead-3QN24ELV.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-FYZOD3SS.js.map +0 -1
- /package/dist/{chunk-EX5XJEGF.js.map → chunk-52V5BMBC.js.map} +0 -0
- /package/dist/{chunk-P7UIFZQO.js.map → chunk-EQK5Q7ZL.js.map} +0 -0
- /package/dist/{claude-pair-runtime-XSUQMCIQ.js.map → claude-pair-runtime-SXEBKHYM.js.map} +0 -0
- /package/dist/{persistent-session-SQWO4TKG.js.map → persistent-session-3OCFA42T.js.map} +0 -0
- /package/dist/{responsiveness-probe-RWMERSER.js.map → responsiveness-probe-ZEKOULXD.js.map} +0 -0
- /package/dist/{session-auth-dead-OOWR5BPI.js.map → session-auth-dead-3QN24ELV.js.map} +0 -0
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
rotateDailySession,
|
|
17
17
|
sessionFileExists,
|
|
18
18
|
todayLocalIso
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-4GA4K2BF.js";
|
|
20
20
|
import {
|
|
21
21
|
reapOrphanChannelMcps
|
|
22
22
|
} from "./chunk-XWVM4KPK.js";
|
|
@@ -4322,4 +4322,4 @@ export {
|
|
|
4322
4322
|
stopAllSessionsAndWait,
|
|
4323
4323
|
getProjectDir
|
|
4324
4324
|
};
|
|
4325
|
-
//# sourceMappingURL=chunk-
|
|
4325
|
+
//# sourceMappingURL=chunk-52V5BMBC.js.map
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
isolationMode,
|
|
9
9
|
log,
|
|
10
10
|
parseEnvIntegrations
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-52V5BMBC.js";
|
|
12
12
|
import {
|
|
13
13
|
BIND_FAILURE_QUARANTINE_THRESHOLD,
|
|
14
14
|
INTEGRATIONS_SECTION_END,
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
resolveConnectivityProbe,
|
|
56
56
|
worseConnectivityOutcome,
|
|
57
57
|
wrapScheduledTaskPrompt
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-4GA4K2BF.js";
|
|
59
59
|
import {
|
|
60
60
|
parsePsRows
|
|
61
61
|
} from "./chunk-XWVM4KPK.js";
|
|
@@ -6342,7 +6342,7 @@ function exchangeFailureKind(err) {
|
|
|
6342
6342
|
}
|
|
6343
6343
|
|
|
6344
6344
|
// src/lib/api-client.ts
|
|
6345
|
-
var agtCliVersion = true ? "0.28.
|
|
6345
|
+
var agtCliVersion = true ? "0.28.668" : "dev";
|
|
6346
6346
|
var lastConfigHash = null;
|
|
6347
6347
|
function setConfigHash(hash) {
|
|
6348
6348
|
lastConfigHash = hash && hash.length > 0 ? hash : null;
|
|
@@ -10084,4 +10084,4 @@ export {
|
|
|
10084
10084
|
managerInstallSystemUnitCommand,
|
|
10085
10085
|
managerUninstallSystemUnitCommand
|
|
10086
10086
|
};
|
|
10087
|
-
//# sourceMappingURL=chunk-
|
|
10087
|
+
//# sourceMappingURL=chunk-EQK5Q7ZL.js.map
|
|
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
|
|
|
100
100
|
return { ok: true };
|
|
101
101
|
} catch {
|
|
102
102
|
}
|
|
103
|
-
const { resolveClaudeBinary } = await import("./persistent-session-
|
|
103
|
+
const { resolveClaudeBinary } = await import("./persistent-session-3OCFA42T.js");
|
|
104
104
|
const claudeBin = resolveClaudeBinary();
|
|
105
105
|
const pairEnv = {
|
|
106
106
|
...process.env,
|
|
@@ -373,4 +373,4 @@ export {
|
|
|
373
373
|
startClaudePair,
|
|
374
374
|
submitClaudePairCode
|
|
375
375
|
};
|
|
376
|
-
//# sourceMappingURL=claude-pair-runtime-
|
|
376
|
+
//# sourceMappingURL=claude-pair-runtime-SXEBKHYM.js.map
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
safeWriteJsonAtomic,
|
|
56
56
|
setConfigHash,
|
|
57
57
|
tripClass
|
|
58
|
-
} from "../chunk-
|
|
58
|
+
} from "../chunk-EQK5Q7ZL.js";
|
|
59
59
|
import {
|
|
60
60
|
getProjectDir as getProjectDir2,
|
|
61
61
|
getReadyTasks,
|
|
@@ -111,7 +111,7 @@ import {
|
|
|
111
111
|
takeZombieDetection,
|
|
112
112
|
toOpencodeModel,
|
|
113
113
|
writeEgressAllowlist
|
|
114
|
-
} from "../chunk-
|
|
114
|
+
} from "../chunk-52V5BMBC.js";
|
|
115
115
|
import {
|
|
116
116
|
ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
|
|
117
117
|
AnchorSessionClient,
|
|
@@ -192,14 +192,14 @@ import {
|
|
|
192
192
|
subagentActivityAgeSeconds,
|
|
193
193
|
sumTranscriptUsageInWindow,
|
|
194
194
|
transcriptActivityAgeSeconds
|
|
195
|
-
} from "../chunk-
|
|
195
|
+
} from "../chunk-4GA4K2BF.js";
|
|
196
196
|
import {
|
|
197
197
|
reapOrphanChannelMcps
|
|
198
198
|
} from "../chunk-XWVM4KPK.js";
|
|
199
199
|
|
|
200
200
|
// src/lib/manager-worker.ts
|
|
201
201
|
import { createHash as createHash17 } from "crypto";
|
|
202
|
-
import { readFileSync as readFileSync28, writeFileSync as writeFileSync14, mkdirSync as mkdirSync11, existsSync as existsSync15, rmSync as rmSync5, readdirSync as readdirSync9, statSync as statSync8 } from "fs";
|
|
202
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync14, mkdirSync as mkdirSync11, existsSync as existsSync15, rmSync as rmSync5, readdirSync as readdirSync9, statSync as statSync8, unlinkSync as unlinkSync6, renameSync as renameSync8, utimesSync } from "fs";
|
|
203
203
|
|
|
204
204
|
// src/lib/atomic-file-replace.ts
|
|
205
205
|
import { copyFileSync, renameSync, unlinkSync } from "fs";
|
|
@@ -11611,7 +11611,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
|
|
|
11611
11611
|
var dayRolloverInboundHold = /* @__PURE__ */ new Map();
|
|
11612
11612
|
var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
|
|
11613
11613
|
async function channelInboundActivityAgeSecondsFor(codeName) {
|
|
11614
|
-
const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-
|
|
11614
|
+
const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-ZEKOULXD.js");
|
|
11615
11615
|
const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
|
|
11616
11616
|
if (newest === null) return null;
|
|
11617
11617
|
return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
|
|
@@ -12256,7 +12256,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
12256
12256
|
var lastVersionCheckAt = 0;
|
|
12257
12257
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
12258
12258
|
var lastResponsivenessProbeAt = 0;
|
|
12259
|
-
var agtCliVersion = true ? "0.28.
|
|
12259
|
+
var agtCliVersion = true ? "0.28.668" : "dev";
|
|
12260
12260
|
function resolveBrewPath(execFileSync3) {
|
|
12261
12261
|
try {
|
|
12262
12262
|
const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -13620,7 +13620,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
|
|
|
13620
13620
|
if (codeNames.length === 0) return;
|
|
13621
13621
|
void (async () => {
|
|
13622
13622
|
try {
|
|
13623
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
13623
|
+
const { collectDiagnostics } = await import("../persistent-session-3OCFA42T.js");
|
|
13624
13624
|
await api.post("/host/heartbeat", {
|
|
13625
13625
|
host_id: hostId,
|
|
13626
13626
|
agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
|
|
@@ -13736,7 +13736,7 @@ async function pollCycleInner() {
|
|
|
13736
13736
|
}
|
|
13737
13737
|
try {
|
|
13738
13738
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
13739
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
13739
|
+
const { collectDiagnostics } = await import("../persistent-session-3OCFA42T.js");
|
|
13740
13740
|
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
13741
13741
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor) : void 0;
|
|
13742
13742
|
let tailscaleHostname;
|
|
@@ -13888,7 +13888,7 @@ async function pollCycleInner() {
|
|
|
13888
13888
|
collectPanelessActivityProbes,
|
|
13889
13889
|
getResponsivenessIntervalMs,
|
|
13890
13890
|
occupancyQualificationClassifications
|
|
13891
|
-
} = await import("../responsiveness-probe-
|
|
13891
|
+
} = await import("../responsiveness-probe-ZEKOULXD.js");
|
|
13892
13892
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
13893
13893
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
13894
13894
|
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
@@ -13998,7 +13998,7 @@ async function pollCycleInner() {
|
|
|
13998
13998
|
collectResponsivenessProbes,
|
|
13999
13999
|
livePendingInboundOldestAgeSeconds,
|
|
14000
14000
|
parkPendingInbound
|
|
14001
|
-
} = await import("../responsiveness-probe-
|
|
14001
|
+
} = await import("../responsiveness-probe-ZEKOULXD.js");
|
|
14002
14002
|
const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
|
|
14003
14003
|
const wedgeNow = /* @__PURE__ */ new Date();
|
|
14004
14004
|
const liveAgents = agentState.persistentSessionAgents;
|
|
@@ -14154,7 +14154,7 @@ async function pollCycleInner() {
|
|
|
14154
14154
|
}
|
|
14155
14155
|
try {
|
|
14156
14156
|
const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
|
|
14157
|
-
const { probeSessionAuth } = await import("../session-auth-dead-
|
|
14157
|
+
const { probeSessionAuth } = await import("../session-auth-dead-3QN24ELV.js");
|
|
14158
14158
|
const observations = [];
|
|
14159
14159
|
const pendingCacheCommits = [];
|
|
14160
14160
|
const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
|
|
@@ -17891,7 +17891,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
|
|
|
17891
17891
|
void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
|
|
17892
17892
|
void (async () => {
|
|
17893
17893
|
try {
|
|
17894
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
17894
|
+
const { collectDiagnostics } = await import("../persistent-session-3OCFA42T.js");
|
|
17895
17895
|
await api.post("/host/heartbeat", {
|
|
17896
17896
|
host_id: hostId,
|
|
17897
17897
|
agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
|
|
@@ -17942,7 +17942,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
|
|
|
17942
17942
|
}
|
|
17943
17943
|
try {
|
|
17944
17944
|
const hostId = await getHostId();
|
|
17945
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
17945
|
+
const { collectDiagnostics } = await import("../persistent-session-3OCFA42T.js");
|
|
17946
17946
|
await api.post("/host/heartbeat", {
|
|
17947
17947
|
host_id: hostId,
|
|
17948
17948
|
agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
|
|
@@ -18573,7 +18573,7 @@ async function processClaudePairSessions(agents) {
|
|
|
18573
18573
|
killPairSession,
|
|
18574
18574
|
pairTmuxSession,
|
|
18575
18575
|
finalizeClaudePairOnboarding
|
|
18576
|
-
} = await import("../claude-pair-runtime-
|
|
18576
|
+
} = await import("../claude-pair-runtime-SXEBKHYM.js");
|
|
18577
18577
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
18578
18578
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
18579
18579
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -18796,6 +18796,68 @@ function generateArtifacts(agent, refreshData, adapter, renderIntegrationsSectio
|
|
|
18796
18796
|
var memoryFileHashes = /* @__PURE__ */ new Map();
|
|
18797
18797
|
var lastDownloadHash = /* @__PURE__ */ new Map();
|
|
18798
18798
|
var lastLocalFileHash = /* @__PURE__ */ new Map();
|
|
18799
|
+
var memoryManifests = /* @__PURE__ */ new Map();
|
|
18800
|
+
function memoryRetirementDir(configDir, codeName) {
|
|
18801
|
+
return join36(configDir, "_memory-retirement", codeName);
|
|
18802
|
+
}
|
|
18803
|
+
function memoryManifestPath(configDir, codeName) {
|
|
18804
|
+
return join36(memoryRetirementDir(configDir, codeName), "manifest.json");
|
|
18805
|
+
}
|
|
18806
|
+
function loadMemoryManifest(agentId, configDir, codeName) {
|
|
18807
|
+
const cached = memoryManifests.get(agentId);
|
|
18808
|
+
if (cached) return cached;
|
|
18809
|
+
let manifest = {};
|
|
18810
|
+
try {
|
|
18811
|
+
const raw = readFileSync28(memoryManifestPath(configDir, codeName), "utf-8");
|
|
18812
|
+
const parsed = JSON.parse(raw);
|
|
18813
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
18814
|
+
for (const [name, entry] of Object.entries(parsed)) {
|
|
18815
|
+
if (entry && typeof entry === "object" && typeof entry.file === "string" && typeof entry.sha === "string") {
|
|
18816
|
+
manifest[name] = { file: entry.file, sha: entry.sha };
|
|
18817
|
+
}
|
|
18818
|
+
}
|
|
18819
|
+
}
|
|
18820
|
+
} catch {
|
|
18821
|
+
manifest = {};
|
|
18822
|
+
}
|
|
18823
|
+
memoryManifests.set(agentId, manifest);
|
|
18824
|
+
return manifest;
|
|
18825
|
+
}
|
|
18826
|
+
function saveMemoryManifest(agentId, configDir, codeName) {
|
|
18827
|
+
const manifest = memoryManifests.get(agentId);
|
|
18828
|
+
if (!manifest) return;
|
|
18829
|
+
try {
|
|
18830
|
+
const path = memoryManifestPath(configDir, codeName);
|
|
18831
|
+
mkdirSync11(memoryRetirementDir(configDir, codeName), { recursive: true });
|
|
18832
|
+
const tmp = `${path}.tmp`;
|
|
18833
|
+
writeFileSync14(tmp, JSON.stringify(manifest, null, 2));
|
|
18834
|
+
renameSync8(tmp, path);
|
|
18835
|
+
} catch {
|
|
18836
|
+
}
|
|
18837
|
+
}
|
|
18838
|
+
function retiredMemoryDir(configDir, codeName) {
|
|
18839
|
+
return join36(memoryRetirementDir(configDir, codeName), "retired");
|
|
18840
|
+
}
|
|
18841
|
+
var RETIRED_MEMORY_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
18842
|
+
var lastRetirementReport = /* @__PURE__ */ new Map();
|
|
18843
|
+
async function reportMemoryRetirement(agent, outcomes, log2) {
|
|
18844
|
+
const fingerprint3 = outcomes.unapplied.map((u) => `${u.reason}:${u.name}`).sort().join("\0");
|
|
18845
|
+
if (lastRetirementReport.get(agent.agent_id) === fingerprint3) return;
|
|
18846
|
+
try {
|
|
18847
|
+
await api.post("/host/memory-retirement-report", {
|
|
18848
|
+
agent_id: agent.agent_id,
|
|
18849
|
+
unapplied: outcomes.unapplied
|
|
18850
|
+
});
|
|
18851
|
+
lastRetirementReport.set(agent.agent_id, fingerprint3);
|
|
18852
|
+
if (outcomes.unapplied.length > 0) {
|
|
18853
|
+
log2(
|
|
18854
|
+
`[memory-retire] ${agent.code_name}: reported ${outcomes.unapplied.length} retired memory file(s) still present on this host`
|
|
18855
|
+
);
|
|
18856
|
+
}
|
|
18857
|
+
} catch (err) {
|
|
18858
|
+
log2(`[memory-retire] ${agent.code_name}: retirement report failed: ${err.message}`);
|
|
18859
|
+
}
|
|
18860
|
+
}
|
|
18799
18861
|
var pendingFreshMemorySync = /* @__PURE__ */ new Set();
|
|
18800
18862
|
function markAgentForFreshMemorySync(agentId) {
|
|
18801
18863
|
pendingFreshMemorySync.add(agentId);
|
|
@@ -18826,17 +18888,131 @@ function parseMemoryFile(raw, fallbackName) {
|
|
|
18826
18888
|
type: isDaily ? "daily" : "project"
|
|
18827
18889
|
};
|
|
18828
18890
|
}
|
|
18891
|
+
function applyMemoryTombstones(opts) {
|
|
18892
|
+
const { agent, configDir, memoryDir, tombstones, truncated, enabled, log: log2 } = opts;
|
|
18893
|
+
const outcomes = {
|
|
18894
|
+
removed: 0,
|
|
18895
|
+
kept_unknown: 0,
|
|
18896
|
+
kept_modified: 0,
|
|
18897
|
+
already_gone: 0,
|
|
18898
|
+
failed: 0,
|
|
18899
|
+
skipped_disabled: 0,
|
|
18900
|
+
unapplied: []
|
|
18901
|
+
};
|
|
18902
|
+
if (tombstones.length === 0) return outcomes;
|
|
18903
|
+
if (!enabled) {
|
|
18904
|
+
outcomes.skipped_disabled = tombstones.length;
|
|
18905
|
+
return outcomes;
|
|
18906
|
+
}
|
|
18907
|
+
const manifest = loadMemoryManifest(agent.agent_id, configDir, agent.code_name);
|
|
18908
|
+
let manifestDirty = false;
|
|
18909
|
+
for (const tomb of tombstones) {
|
|
18910
|
+
const entry = manifest[tomb.name];
|
|
18911
|
+
if (!entry) {
|
|
18912
|
+
outcomes.kept_unknown++;
|
|
18913
|
+
outcomes.unapplied.push({ name: tomb.name, reason: "kept_unknown" });
|
|
18914
|
+
log2(`[memory-retire] ${agent.code_name}: KEPT '${tomb.name}' \u2014 no write record, not ours to remove`);
|
|
18915
|
+
continue;
|
|
18916
|
+
}
|
|
18917
|
+
const filePath = join36(memoryDir, entry.file);
|
|
18918
|
+
if (!existsSync15(filePath)) {
|
|
18919
|
+
outcomes.already_gone++;
|
|
18920
|
+
delete manifest[tomb.name];
|
|
18921
|
+
manifestDirty = true;
|
|
18922
|
+
continue;
|
|
18923
|
+
}
|
|
18924
|
+
try {
|
|
18925
|
+
const actual = createHash17("sha256").update(readFileSync28(filePath)).digest("hex");
|
|
18926
|
+
if (actual !== entry.sha) {
|
|
18927
|
+
outcomes.kept_modified++;
|
|
18928
|
+
outcomes.unapplied.push({ name: tomb.name, reason: "kept_modified" });
|
|
18929
|
+
log2(
|
|
18930
|
+
`[memory-retire] ${agent.code_name}: KEPT '${tomb.name}' (${entry.file}) \u2014 edited since we wrote it (recorded ${entry.sha.slice(0, 12)}, on disk ${actual.slice(0, 12)})`
|
|
18931
|
+
);
|
|
18932
|
+
continue;
|
|
18933
|
+
}
|
|
18934
|
+
const destDir = retiredMemoryDir(configDir, agent.code_name);
|
|
18935
|
+
mkdirSync11(destDir, { recursive: true });
|
|
18936
|
+
const stamp = Date.now();
|
|
18937
|
+
let dest = join36(destDir, `${entry.file}.${stamp}.retired`);
|
|
18938
|
+
for (let n = 1; existsSync15(dest); n++) {
|
|
18939
|
+
dest = join36(destDir, `${entry.file}.${stamp}-${n}.retired`);
|
|
18940
|
+
}
|
|
18941
|
+
renameSync8(filePath, dest);
|
|
18942
|
+
try {
|
|
18943
|
+
const now = Date.now() / 1e3;
|
|
18944
|
+
utimesSync(dest, now, now);
|
|
18945
|
+
} catch {
|
|
18946
|
+
}
|
|
18947
|
+
delete manifest[tomb.name];
|
|
18948
|
+
manifestDirty = true;
|
|
18949
|
+
memoryFileHashes.get(agent.agent_id)?.delete(entry.file);
|
|
18950
|
+
outcomes.removed++;
|
|
18951
|
+
log2(`[memory-retire] ${agent.code_name}: removed '${tomb.name}' (${entry.file})`);
|
|
18952
|
+
} catch (err) {
|
|
18953
|
+
outcomes.failed++;
|
|
18954
|
+
outcomes.unapplied.push({ name: tomb.name, reason: "failed" });
|
|
18955
|
+
log2(`[memory-retire] ${agent.code_name}: FAILED '${tomb.name}': ${err.message}`);
|
|
18956
|
+
}
|
|
18957
|
+
}
|
|
18958
|
+
if (manifestDirty) saveMemoryManifest(agent.agent_id, configDir, agent.code_name);
|
|
18959
|
+
log2(
|
|
18960
|
+
`[memory-retire] ${agent.code_name}: ${tombstones.length} tombstone(s) \u2014 ${outcomes.removed} removed, ${outcomes.kept_modified} kept (edited), ${outcomes.kept_unknown} kept (not ours), ${outcomes.already_gone} already gone, ${outcomes.failed} failed`
|
|
18961
|
+
);
|
|
18962
|
+
if (truncated) {
|
|
18963
|
+
log2(
|
|
18964
|
+
`[memory-retire] ${agent.code_name}: tombstone list was TRUNCATED by the server \u2014 older retirements are permanently absent from it and their files cannot be reached`
|
|
18965
|
+
);
|
|
18966
|
+
}
|
|
18967
|
+
reapRetiredMemories(configDir, agent.code_name, log2);
|
|
18968
|
+
return outcomes;
|
|
18969
|
+
}
|
|
18970
|
+
function reapRetiredMemories(configDir, codeName, log2) {
|
|
18971
|
+
const dir = retiredMemoryDir(configDir, codeName);
|
|
18972
|
+
if (!existsSync15(dir)) return;
|
|
18973
|
+
const cutoff = Date.now() - RETIRED_MEMORY_TTL_MS;
|
|
18974
|
+
let reaped = 0;
|
|
18975
|
+
try {
|
|
18976
|
+
for (const file of readdirSync9(dir)) {
|
|
18977
|
+
if (!file.endsWith(".retired")) continue;
|
|
18978
|
+
const path = join36(dir, file);
|
|
18979
|
+
try {
|
|
18980
|
+
if (statSync8(path).mtimeMs < cutoff) {
|
|
18981
|
+
unlinkSync6(path);
|
|
18982
|
+
reaped++;
|
|
18983
|
+
}
|
|
18984
|
+
} catch {
|
|
18985
|
+
}
|
|
18986
|
+
}
|
|
18987
|
+
} catch {
|
|
18988
|
+
return;
|
|
18989
|
+
}
|
|
18990
|
+
if (reaped > 0) log2(`[memory-retire] ${codeName}: reaped ${reaped} retired memory file(s) past TTL`);
|
|
18991
|
+
}
|
|
18829
18992
|
async function syncMemories(agent, configDir, log2) {
|
|
18830
18993
|
const projectDir = join36(configDir, agent.code_name, "project");
|
|
18831
18994
|
const memoryDir = join36(projectDir, "memory");
|
|
18832
18995
|
const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
|
|
18833
18996
|
if (isFreshSync) {
|
|
18834
18997
|
log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
|
|
18835
|
-
const
|
|
18836
|
-
if (
|
|
18998
|
+
const result = await downloadMemories(agent, memoryDir, log2, { force: true, configDir });
|
|
18999
|
+
if (result.status === "failed") {
|
|
18837
19000
|
log2(`[memory-sync] Fresh-sync download failed for '${agent.code_name}' \u2014 skipping upload, will retry next tick`);
|
|
18838
19001
|
return;
|
|
18839
19002
|
}
|
|
19003
|
+
if (result.tombstones) {
|
|
19004
|
+
const tombEnabled = hostFlagStore().getBooleanForAgent("memory-file-tombstones", agent.agent_id);
|
|
19005
|
+
const tombOutcomes = applyMemoryTombstones({
|
|
19006
|
+
agent,
|
|
19007
|
+
configDir,
|
|
19008
|
+
memoryDir,
|
|
19009
|
+
tombstones: result.tombstones,
|
|
19010
|
+
truncated: result.truncated,
|
|
19011
|
+
enabled: tombEnabled,
|
|
19012
|
+
log: log2
|
|
19013
|
+
});
|
|
19014
|
+
if (tombEnabled) await reportMemoryRetirement(agent, tombOutcomes, log2);
|
|
19015
|
+
}
|
|
18840
19016
|
pendingFreshMemorySync.delete(agent.agent_id);
|
|
18841
19017
|
}
|
|
18842
19018
|
if (existsSync15(memoryDir)) {
|
|
@@ -18880,10 +19056,23 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
18880
19056
|
}
|
|
18881
19057
|
}
|
|
18882
19058
|
if (!isFreshSync) {
|
|
18883
|
-
await downloadMemories(agent, memoryDir, log2, { force: false });
|
|
19059
|
+
const result = await downloadMemories(agent, memoryDir, log2, { force: false, configDir });
|
|
19060
|
+
if (result.status !== "failed" && result.tombstones) {
|
|
19061
|
+
const tombEnabled = hostFlagStore().getBooleanForAgent("memory-file-tombstones", agent.agent_id);
|
|
19062
|
+
const tombOutcomes = applyMemoryTombstones({
|
|
19063
|
+
agent,
|
|
19064
|
+
configDir,
|
|
19065
|
+
memoryDir,
|
|
19066
|
+
tombstones: result.tombstones,
|
|
19067
|
+
truncated: result.truncated,
|
|
19068
|
+
enabled: tombEnabled,
|
|
19069
|
+
log: log2
|
|
19070
|
+
});
|
|
19071
|
+
if (tombEnabled) await reportMemoryRetirement(agent, tombOutcomes, log2);
|
|
19072
|
+
}
|
|
18884
19073
|
}
|
|
18885
19074
|
}
|
|
18886
|
-
async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
19075
|
+
async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
|
|
18887
19076
|
const localFiles = existsSync15(memoryDir) ? readdirSync9(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
|
|
18888
19077
|
const localListHash = createHash17("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
|
|
18889
19078
|
const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
|
|
@@ -18892,21 +19081,24 @@ async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
|
18892
19081
|
const dbMemories = await api.post("/host/memories", {
|
|
18893
19082
|
agent_id: agent.agent_id
|
|
18894
19083
|
});
|
|
18895
|
-
const
|
|
19084
|
+
const tombstones = Array.isArray(dbMemories.tombstones) ? dbMemories.tombstones : null;
|
|
19085
|
+
const responseHash = createHash17("sha256").update(JSON.stringify({ m: dbMemories.memories ?? [], t: tombstones })).digest("hex").slice(0, 16);
|
|
18896
19086
|
if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
|
|
18897
|
-
return true;
|
|
19087
|
+
return { status: "skipped", tombstones, truncated: dbMemories.tombstones_truncated === true };
|
|
18898
19088
|
}
|
|
18899
19089
|
lastDownloadHash.set(agent.agent_id, responseHash);
|
|
18900
19090
|
lastLocalFileHash.set(agent.agent_id, localListHash);
|
|
18901
19091
|
if (dbMemories.memories?.length) {
|
|
18902
19092
|
mkdirSync11(memoryDir, { recursive: true });
|
|
19093
|
+
const manifest = loadMemoryManifest(agent.agent_id, configDir, agent.code_name);
|
|
18903
19094
|
let written = 0;
|
|
18904
19095
|
let overwritten = 0;
|
|
18905
19096
|
for (let i = 0; i < dbMemories.memories.length; i++) {
|
|
18906
19097
|
const mem = dbMemories.memories[i];
|
|
18907
19098
|
const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
|
|
18908
19099
|
const slug = rawSlug || `memory-${i}`;
|
|
18909
|
-
const
|
|
19100
|
+
const fileName = `${slug}.md`;
|
|
19101
|
+
const filePath = join36(memoryDir, fileName);
|
|
18910
19102
|
const desired = `---
|
|
18911
19103
|
name: ${JSON.stringify(mem.name)}
|
|
18912
19104
|
type: ${mem.type}
|
|
@@ -18915,19 +19107,33 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
|
|
|
18915
19107
|
|
|
18916
19108
|
${mem.content}
|
|
18917
19109
|
`;
|
|
19110
|
+
const record = () => {
|
|
19111
|
+
const sha = createHash17("sha256").update(desired).digest("hex");
|
|
19112
|
+
const prev = manifest[mem.name];
|
|
19113
|
+
if (prev?.file === fileName && prev.sha === sha) return false;
|
|
19114
|
+
manifest[mem.name] = { file: fileName, sha };
|
|
19115
|
+
return true;
|
|
19116
|
+
};
|
|
19117
|
+
let manifestDirty = false;
|
|
18918
19118
|
if (existsSync15(filePath)) {
|
|
18919
19119
|
let existing = "";
|
|
18920
19120
|
try {
|
|
18921
19121
|
existing = readFileSync28(filePath, "utf-8");
|
|
18922
19122
|
} catch {
|
|
18923
19123
|
}
|
|
18924
|
-
if (existing === desired)
|
|
19124
|
+
if (existing === desired) {
|
|
19125
|
+
if (record()) manifestDirty = true;
|
|
19126
|
+
if (manifestDirty) saveMemoryManifest(agent.agent_id, configDir, agent.code_name);
|
|
19127
|
+
continue;
|
|
19128
|
+
}
|
|
18925
19129
|
writeFileSync14(filePath, desired);
|
|
18926
19130
|
overwritten++;
|
|
18927
19131
|
} else {
|
|
18928
19132
|
writeFileSync14(filePath, desired);
|
|
18929
19133
|
written++;
|
|
18930
19134
|
}
|
|
19135
|
+
if (record()) manifestDirty = true;
|
|
19136
|
+
if (manifestDirty) saveMemoryManifest(agent.agent_id, configDir, agent.code_name);
|
|
18931
19137
|
}
|
|
18932
19138
|
if (written > 0 || overwritten > 0) {
|
|
18933
19139
|
const updatedFiles = readdirSync9(memoryDir).filter((f) => f.endsWith(".md")).sort();
|
|
@@ -18935,10 +19141,10 @@ ${mem.content}
|
|
|
18935
19141
|
log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
|
|
18936
19142
|
}
|
|
18937
19143
|
}
|
|
18938
|
-
return true;
|
|
19144
|
+
return { status: "fetched", tombstones, truncated: dbMemories.tombstones_truncated === true };
|
|
18939
19145
|
} catch (err) {
|
|
18940
19146
|
log2(`Memory download failed for '${agent.code_name}': ${err.message}`);
|
|
18941
|
-
return false;
|
|
19147
|
+
return { status: "failed", tombstones: null, truncated: false };
|
|
18942
19148
|
}
|
|
18943
19149
|
}
|
|
18944
19150
|
async function cleanupAgentFiles(codeName, agentDir) {
|
|
@@ -19550,6 +19756,7 @@ export {
|
|
|
19550
19756
|
REALTIME_REBIND_MAX_BACKOFF_MS,
|
|
19551
19757
|
REALTIME_REBIND_STUCK_AFTER_MS,
|
|
19552
19758
|
UntrustworthyToolkitResponseError,
|
|
19759
|
+
applyMemoryTombstones,
|
|
19553
19760
|
applyRestartAcks,
|
|
19554
19761
|
cancelKanbanNoticeOnDrain,
|
|
19555
19762
|
channelSyncBackoffMs,
|
|
@@ -19578,6 +19785,8 @@ export {
|
|
|
19578
19785
|
maybeInjectKanbanCheck,
|
|
19579
19786
|
maybeProbeClaudeRuntimeAuth,
|
|
19580
19787
|
maybeUpgradeClaudeCode,
|
|
19788
|
+
memoryManifestPath,
|
|
19789
|
+
memoryManifests,
|
|
19581
19790
|
pruneRealtimeRebindState,
|
|
19582
19791
|
realtimeRebindBackoffMs,
|
|
19583
19792
|
realtimeRebindDue,
|
|
@@ -19587,6 +19796,7 @@ export {
|
|
|
19587
19796
|
reorderRestartedFirst,
|
|
19588
19797
|
resolveManagedMcpServerId,
|
|
19589
19798
|
restartReasonBindsNewMcp,
|
|
19799
|
+
retiredMemoryDir,
|
|
19590
19800
|
sameChannelSet,
|
|
19591
19801
|
shouldLogChannelSyncFailure,
|
|
19592
19802
|
shouldReapOnRetag,
|