@integrity-labs/agt-cli 0.27.128 → 0.27.130
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 +4 -4
- package/dist/{chunk-TXZLQK3S.js → chunk-H4QCCP2M.js} +30 -9
- package/dist/chunk-H4QCCP2M.js.map +1 -0
- package/dist/{chunk-QON5CU3L.js → chunk-JQOOOLKR.js} +2 -2
- package/dist/{chunk-MH7HA6QV.js → chunk-XCV5NU45.js} +8 -2
- package/dist/chunk-XCV5NU45.js.map +1 -0
- package/dist/{claude-pair-runtime-QNOWFDJ7.js → claude-pair-runtime-GWZWHISO.js} +2 -2
- package/dist/lib/manager-worker.js +267 -87
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{persistent-session-PJQZYG2L.js → persistent-session-NTO2PO2V.js} +3 -3
- package/dist/{responsiveness-probe-MGMZQSP7.js → responsiveness-probe-BG7O5UIG.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-MH7HA6QV.js.map +0 -1
- package/dist/chunk-TXZLQK3S.js.map +0 -1
- /package/dist/{chunk-QON5CU3L.js.map → chunk-JQOOOLKR.js.map} +0 -0
- /package/dist/{claude-pair-runtime-QNOWFDJ7.js.map → claude-pair-runtime-GWZWHISO.js.map} +0 -0
- /package/dist/{persistent-session-PJQZYG2L.js.map → persistent-session-NTO2PO2V.js.map} +0 -0
- /package/dist/{responsiveness-probe-MGMZQSP7.js.map → responsiveness-probe-BG7O5UIG.js.map} +0 -0
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
provisionStopHook,
|
|
18
18
|
requireHost,
|
|
19
19
|
safeWriteJsonAtomic
|
|
20
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-H4QCCP2M.js";
|
|
21
21
|
import {
|
|
22
22
|
getProjectDir as getProjectDir2,
|
|
23
23
|
getReadyTasks,
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
stopPersistentSession,
|
|
57
57
|
takeWatchdogGiveUpCount,
|
|
58
58
|
takeZombieDetection
|
|
59
|
-
} from "../chunk-
|
|
59
|
+
} from "../chunk-JQOOOLKR.js";
|
|
60
60
|
import {
|
|
61
61
|
KANBAN_CHECK_COMMAND,
|
|
62
62
|
SUPPRESS_SENTINEL,
|
|
@@ -83,7 +83,7 @@ import {
|
|
|
83
83
|
resolveDmTarget,
|
|
84
84
|
worseConnectivityOutcome,
|
|
85
85
|
wrapScheduledTaskPrompt
|
|
86
|
-
} from "../chunk-
|
|
86
|
+
} from "../chunk-XCV5NU45.js";
|
|
87
87
|
import {
|
|
88
88
|
parsePsRows,
|
|
89
89
|
reapOrphanChannelMcps
|
|
@@ -502,14 +502,14 @@ function reapMissingMcpSessions(args) {
|
|
|
502
502
|
if (!missingRaw.includes(key)) liveKeys.add(key);
|
|
503
503
|
}
|
|
504
504
|
for (const key of liveKeys) {
|
|
505
|
-
const
|
|
506
|
-
if (
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
505
|
+
const state7 = presenceReaperState.get(stateKey(codeName, key));
|
|
506
|
+
if (state7) {
|
|
507
|
+
state7.attempts = 0;
|
|
508
|
+
state7.lastSeenLiveAt = now();
|
|
509
|
+
state7.lastAttemptedSessionStartedAt = null;
|
|
510
|
+
state7.gaveUpLogged = false;
|
|
511
|
+
state7.firstMissingAt = null;
|
|
512
|
+
state7.quarantineLogged = false;
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
515
|
if (missing.length === 0) {
|
|
@@ -527,7 +527,7 @@ function reapMissingMcpSessions(args) {
|
|
|
527
527
|
const wouldQuarantine = [];
|
|
528
528
|
for (const key of missing) {
|
|
529
529
|
const sk = stateKey(codeName, key);
|
|
530
|
-
const
|
|
530
|
+
const state7 = presenceReaperState.get(sk) ?? {
|
|
531
531
|
attempts: 0,
|
|
532
532
|
lastSeenLiveAt: null,
|
|
533
533
|
lastAttemptedSessionStartedAt: null,
|
|
@@ -535,19 +535,19 @@ function reapMissingMcpSessions(args) {
|
|
|
535
535
|
firstMissingAt: null,
|
|
536
536
|
quarantineLogged: false
|
|
537
537
|
};
|
|
538
|
-
if (
|
|
539
|
-
if (
|
|
540
|
-
|
|
541
|
-
|
|
538
|
+
if (state7.firstMissingAt === null) state7.firstMissingAt = nowMs;
|
|
539
|
+
if (state7.lastAttemptedSessionStartedAt !== sessionStartedAt) {
|
|
540
|
+
state7.attempts += 1;
|
|
541
|
+
state7.lastAttemptedSessionStartedAt = sessionStartedAt;
|
|
542
542
|
}
|
|
543
|
-
presenceReaperState.set(sk,
|
|
544
|
-
if (
|
|
543
|
+
presenceReaperState.set(sk, state7);
|
|
544
|
+
if (state7.attempts > MAX_PRESENCE_RESTART_ATTEMPTS) {
|
|
545
545
|
givenUp.push(key);
|
|
546
|
-
if (!
|
|
546
|
+
if (!state7.gaveUpLogged) {
|
|
547
547
|
log2(
|
|
548
548
|
`[mcp-presence-reaper] giving up on '${codeName}:${key}' after ${MAX_PRESENCE_RESTART_ATTEMPTS} consecutive failed restarts \u2014 declared but never recovers (likely orphaned config; see ENG-5279)`
|
|
549
549
|
);
|
|
550
|
-
|
|
550
|
+
state7.gaveUpLogged = true;
|
|
551
551
|
if (onGiveUp) {
|
|
552
552
|
try {
|
|
553
553
|
onGiveUp(codeName, key);
|
|
@@ -558,10 +558,10 @@ function reapMissingMcpSessions(args) {
|
|
|
558
558
|
}
|
|
559
559
|
}
|
|
560
560
|
}
|
|
561
|
-
if (quarantineMode !== "off" && !
|
|
562
|
-
const dwellElapsed = quarantineDwellMs <= 0 ||
|
|
561
|
+
if (quarantineMode !== "off" && !state7.quarantineLogged && classifyKey(key) === "optional") {
|
|
562
|
+
const dwellElapsed = quarantineDwellMs <= 0 || state7.firstMissingAt !== null && nowMs - state7.firstMissingAt >= quarantineDwellMs;
|
|
563
563
|
if (dwellElapsed) {
|
|
564
|
-
|
|
564
|
+
state7.quarantineLogged = true;
|
|
565
565
|
if (quarantineMode === "enforce") {
|
|
566
566
|
quarantined.push(key);
|
|
567
567
|
log2(
|
|
@@ -2101,14 +2101,173 @@ function readRecentTurns(dir, nowMs) {
|
|
|
2101
2101
|
return turns;
|
|
2102
2102
|
}
|
|
2103
2103
|
|
|
2104
|
+
// src/lib/memory-extractor.ts
|
|
2105
|
+
var MIN_CHECK_INTERVAL_MS4 = 10 * 6e4;
|
|
2106
|
+
var WINDOW_PAD_MS2 = 5 * 6e4;
|
|
2107
|
+
var VALID_MEMORY_TYPES = /* @__PURE__ */ new Set(["user", "feedback", "project", "reference"]);
|
|
2108
|
+
var SECRET_PATTERNS = [
|
|
2109
|
+
// labelled secrets: `api_key=...`, `password: ...`, `bearer ...`
|
|
2110
|
+
/\b[\w-]*(?:secret|password|passwd|token|api[_-]?key|bearer)[\w-]*\s*[=:]\s*\S+/gi,
|
|
2111
|
+
// common credential prefixes (stripe, github, slack, augmented host keys, …)
|
|
2112
|
+
/\b(?:sk|pk|rk|tlk|ghp|gho|ghs|xox[baprs])[-_][A-Za-z0-9]{12,}\b/g,
|
|
2113
|
+
// long hex blobs (hashes / hex-encoded keys)
|
|
2114
|
+
/\b[A-Fa-f0-9]{32,}\b/g,
|
|
2115
|
+
// long base64 blobs (tokens / encoded secrets)
|
|
2116
|
+
/\b[A-Za-z0-9+/]{40,}={0,2}\b/g,
|
|
2117
|
+
// email addresses
|
|
2118
|
+
/\b[\w.+-]+@[\w-]+\.[\w.-]+\b/g
|
|
2119
|
+
];
|
|
2120
|
+
function scrubSensitive(text) {
|
|
2121
|
+
let out = text;
|
|
2122
|
+
for (const re of SECRET_PATTERNS) out = out.replace(re, "[redacted]");
|
|
2123
|
+
return out;
|
|
2124
|
+
}
|
|
2125
|
+
var state4 = /* @__PURE__ */ new Map();
|
|
2126
|
+
function buildExtractionPrompt(channel, transcript) {
|
|
2127
|
+
return `You are extracting durable, reusable memories from one completed ${channel} conversation between an AI agent and an end-user. A good memory is a stable preference, fact, correction, or recurring work context that will help the agent in FUTURE conversations \u2014 not a one-off task detail or pleasantry.
|
|
2128
|
+
|
|
2129
|
+
Conversation transcript:
|
|
2130
|
+
"""
|
|
2131
|
+
${transcript}
|
|
2132
|
+
"""
|
|
2133
|
+
|
|
2134
|
+
Extract 0-5 candidate memories. For each:
|
|
2135
|
+
- name: short descriptive title (max 50 chars)
|
|
2136
|
+
- content: the memory itself, self-contained (max 200 chars). Do NOT include secrets or sensitive personal data.
|
|
2137
|
+
- type: "user" (a person's stable preference), "feedback" (a correction to how the agent should work), "project" (durable work context), or "reference" (a pointer to an external resource)
|
|
2138
|
+
- confidence: 0.0-1.0 \u2014 how sure you are this is worth remembering long-term
|
|
2139
|
+
- rationale: why this should persist (max 100 chars)
|
|
2140
|
+
|
|
2141
|
+
If there is nothing durable worth remembering, return an empty array. Do NOT invent memories to fill the list.
|
|
2142
|
+
|
|
2143
|
+
Respond with ONLY a JSON array, no other text:
|
|
2144
|
+
[{"name":"...","content":"...","type":"...","confidence":0.8,"rationale":"..."}]`;
|
|
2145
|
+
}
|
|
2146
|
+
function parseCandidates(raw) {
|
|
2147
|
+
const match = raw.match(/\[[\s\S]*\]/);
|
|
2148
|
+
if (!match) return null;
|
|
2149
|
+
let arr;
|
|
2150
|
+
try {
|
|
2151
|
+
arr = JSON.parse(match[0]);
|
|
2152
|
+
} catch {
|
|
2153
|
+
return null;
|
|
2154
|
+
}
|
|
2155
|
+
if (!Array.isArray(arr)) return null;
|
|
2156
|
+
const out = [];
|
|
2157
|
+
for (const entry of arr) {
|
|
2158
|
+
if (!entry || typeof entry !== "object") continue;
|
|
2159
|
+
const c = entry;
|
|
2160
|
+
const name = typeof c.name === "string" ? c.name.trim() : "";
|
|
2161
|
+
if (!name) continue;
|
|
2162
|
+
if (typeof c.type !== "string" || !VALID_MEMORY_TYPES.has(c.type)) continue;
|
|
2163
|
+
const confidence = typeof c.confidence === "number" && Number.isFinite(c.confidence) ? Math.max(0, Math.min(1, c.confidence)) : 0;
|
|
2164
|
+
if (confidence === 0) continue;
|
|
2165
|
+
out.push({
|
|
2166
|
+
name: name.slice(0, 80),
|
|
2167
|
+
content: (typeof c.content === "string" ? c.content : "").trim().slice(0, 500),
|
|
2168
|
+
type: c.type,
|
|
2169
|
+
confidence,
|
|
2170
|
+
rationale: (typeof c.rationale === "string" ? c.rationale : "").trim().slice(0, 200)
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2173
|
+
return out;
|
|
2174
|
+
}
|
|
2175
|
+
async function maybeExtractMemories(args) {
|
|
2176
|
+
const { api: api2, backend, codeName, agentId, log: log2 } = args;
|
|
2177
|
+
const now = args.now ?? /* @__PURE__ */ new Date();
|
|
2178
|
+
const nowMs = now.getTime();
|
|
2179
|
+
const existing = state4.get(codeName);
|
|
2180
|
+
if (existing && nowMs - existing.lastCheckedAt < MIN_CHECK_INTERVAL_MS4) {
|
|
2181
|
+
return;
|
|
2182
|
+
}
|
|
2183
|
+
state4.set(codeName, { lastCheckedAt: nowMs });
|
|
2184
|
+
let pending;
|
|
2185
|
+
try {
|
|
2186
|
+
const resp = await api2.get(
|
|
2187
|
+
`/host/memories/pending-extraction?agent_id=${encodeURIComponent(agentId)}`
|
|
2188
|
+
);
|
|
2189
|
+
pending = resp?.conversations ?? [];
|
|
2190
|
+
} catch (err) {
|
|
2191
|
+
log2(`[memory-extract] ${codeName}: pending fetch failed: ${err.message}`);
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
if (pending.length === 0) return;
|
|
2195
|
+
const dir = args.transcriptDir ?? sessionTranscriptDir(getProjectDir(codeName));
|
|
2196
|
+
const allTurns = readRecentTurns(dir, nowMs);
|
|
2197
|
+
if (allTurns.length === 0) {
|
|
2198
|
+
for (const conv of pending) {
|
|
2199
|
+
await reportSkip2(api2, agentId, conv.conversation_id, log2, codeName);
|
|
2200
|
+
}
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2203
|
+
for (const conv of pending) {
|
|
2204
|
+
const tokens = channelRefTokens(conv.channel_ref);
|
|
2205
|
+
const windowStart = Date.parse(conv.started_at) - WINDOW_PAD_MS2;
|
|
2206
|
+
const windowEnd = Date.parse(conv.last_message_at) + WINDOW_PAD_MS2;
|
|
2207
|
+
const turns = reconstructConversation(allTurns, tokens, windowStart, windowEnd);
|
|
2208
|
+
if (turns.length === 0) {
|
|
2209
|
+
await reportSkip2(api2, agentId, conv.conversation_id, log2, codeName);
|
|
2210
|
+
continue;
|
|
2211
|
+
}
|
|
2212
|
+
const transcript = renderTranscript(turns);
|
|
2213
|
+
if (!transcript.trim()) {
|
|
2214
|
+
await reportSkip2(api2, agentId, conv.conversation_id, log2, codeName);
|
|
2215
|
+
continue;
|
|
2216
|
+
}
|
|
2217
|
+
let candidates;
|
|
2218
|
+
try {
|
|
2219
|
+
const out = await backend.run(buildExtractionPrompt(conv.channel, transcript));
|
|
2220
|
+
candidates = parseCandidates(out);
|
|
2221
|
+
} catch (err) {
|
|
2222
|
+
log2(`[memory-extract] ${codeName}: extraction failed: ${err.message}`);
|
|
2223
|
+
continue;
|
|
2224
|
+
}
|
|
2225
|
+
if (candidates === null) {
|
|
2226
|
+
log2(`[memory-extract] ${codeName}: unparseable output for ${conv.conversation_id.slice(0, 8)} \u2014 will retry`);
|
|
2227
|
+
continue;
|
|
2228
|
+
}
|
|
2229
|
+
const scrubbed = candidates.map((c) => ({
|
|
2230
|
+
...c,
|
|
2231
|
+
content: scrubSensitive(c.content),
|
|
2232
|
+
rationale: scrubSensitive(c.rationale)
|
|
2233
|
+
}));
|
|
2234
|
+
try {
|
|
2235
|
+
const res = await api2.post(
|
|
2236
|
+
"/host/memories/candidates",
|
|
2237
|
+
{
|
|
2238
|
+
agent_id: agentId,
|
|
2239
|
+
conversation_id: conv.conversation_id,
|
|
2240
|
+
candidates: scrubbed
|
|
2241
|
+
}
|
|
2242
|
+
);
|
|
2243
|
+
log2(
|
|
2244
|
+
`[memory-extract] ${codeName}: ${conv.conversation_id.slice(0, 8)} \u2192 ${candidates.length} candidate(s), ${res?.promoted ?? 0} promoted`
|
|
2245
|
+
);
|
|
2246
|
+
} catch (err) {
|
|
2247
|
+
log2(`[memory-extract] ${codeName}: report failed: ${err.message}`);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
async function reportSkip2(api2, agentId, conversationId, log2, codeName) {
|
|
2252
|
+
try {
|
|
2253
|
+
await api2.post("/host/memories/candidates", {
|
|
2254
|
+
agent_id: agentId,
|
|
2255
|
+
conversation_id: conversationId,
|
|
2256
|
+
skipped: true
|
|
2257
|
+
});
|
|
2258
|
+
} catch (err) {
|
|
2259
|
+
log2(`[memory-extract] ${codeName}: skip report failed: ${err.message}`);
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2104
2263
|
// src/lib/activity-cache-monitor.ts
|
|
2105
2264
|
import { existsSync as existsSync2, readFileSync as readFileSync6 } from "fs";
|
|
2106
2265
|
import { homedir } from "os";
|
|
2107
2266
|
import { join as join4 } from "path";
|
|
2108
|
-
var
|
|
2267
|
+
var MIN_CHECK_INTERVAL_MS5 = 6e4;
|
|
2109
2268
|
var STATS_CACHE_PATH = join4(homedir(), ".claude", "stats-cache.json");
|
|
2110
2269
|
var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
2111
|
-
var
|
|
2270
|
+
var state5 = { lastObservedDate: null, lastCheckedAt: 0 };
|
|
2112
2271
|
function selectNewDailyRows(raw, lastObservedDate) {
|
|
2113
2272
|
let parsed;
|
|
2114
2273
|
try {
|
|
@@ -2147,8 +2306,8 @@ async function maybeReportActivityCache(args) {
|
|
|
2147
2306
|
const { api: api2, log: log2 } = args;
|
|
2148
2307
|
const now = args.now ?? /* @__PURE__ */ new Date();
|
|
2149
2308
|
const nowMs = now.getTime();
|
|
2150
|
-
if (nowMs -
|
|
2151
|
-
|
|
2309
|
+
if (nowMs - state5.lastCheckedAt < MIN_CHECK_INTERVAL_MS5) return;
|
|
2310
|
+
state5.lastCheckedAt = nowMs;
|
|
2152
2311
|
if (!existsSync2(STATS_CACHE_PATH)) {
|
|
2153
2312
|
return;
|
|
2154
2313
|
}
|
|
@@ -2159,12 +2318,12 @@ async function maybeReportActivityCache(args) {
|
|
|
2159
2318
|
log2(`[activity-cache] readFileSync failed: ${err.message}`);
|
|
2160
2319
|
return;
|
|
2161
2320
|
}
|
|
2162
|
-
const rows = selectNewDailyRows(raw,
|
|
2321
|
+
const rows = selectNewDailyRows(raw, state5.lastObservedDate);
|
|
2163
2322
|
if (rows.length === 0) return;
|
|
2164
2323
|
for (const row of rows) {
|
|
2165
2324
|
try {
|
|
2166
2325
|
await api2.post("/host/activity-observations", row);
|
|
2167
|
-
|
|
2326
|
+
state5.lastObservedDate = row.date;
|
|
2168
2327
|
} catch (err) {
|
|
2169
2328
|
log2(
|
|
2170
2329
|
`[activity-cache] POST /host/activity-observations failed for date=${row.date}: ${err.message}`
|
|
@@ -3278,10 +3437,10 @@ function recordWedgeForCards(states, inProgressCardIds, nowMs, config2) {
|
|
|
3278
3437
|
function pruneCardStates(states, liveInProgressCardIds, nowMs, config2) {
|
|
3279
3438
|
const live = liveInProgressCardIds instanceof Set ? liveInProgressCardIds : new Set(liveInProgressCardIds);
|
|
3280
3439
|
const next = /* @__PURE__ */ new Map();
|
|
3281
|
-
for (const [id,
|
|
3440
|
+
for (const [id, state7] of states) {
|
|
3282
3441
|
if (!live.has(id)) continue;
|
|
3283
|
-
if (nowMs -
|
|
3284
|
-
next.set(id,
|
|
3442
|
+
if (nowMs - state7.lastWedgeAtMs > config2.cooldownMs) continue;
|
|
3443
|
+
next.set(id, state7);
|
|
3285
3444
|
}
|
|
3286
3445
|
return next;
|
|
3287
3446
|
}
|
|
@@ -3971,8 +4130,8 @@ var KNOWN_SAFE_TAIL_SIGNATURES = /* @__PURE__ */ new Set(["session_id_in_use"]);
|
|
|
3971
4130
|
function shouldSkipRevokedCleanup(previousKnownStatus) {
|
|
3972
4131
|
return previousKnownStatus === "revoked";
|
|
3973
4132
|
}
|
|
3974
|
-
function hasRevokedResiduals(
|
|
3975
|
-
return
|
|
4133
|
+
function hasRevokedResiduals(state7) {
|
|
4134
|
+
return state7.gatewayRunning || state7.portAllocated || state7.provisionDirExists;
|
|
3976
4135
|
}
|
|
3977
4136
|
var pendingSessionRestarts = /* @__PURE__ */ new Map();
|
|
3978
4137
|
var pendingRestartVerifications = /* @__PURE__ */ new Map();
|
|
@@ -4077,12 +4236,12 @@ function maybeAutoResume(agent) {
|
|
|
4077
4236
|
autoResumeMarkers.set(codeName, { trippedAt, autoResumedAt: Date.now() });
|
|
4078
4237
|
restartBreaker.clear(codeName);
|
|
4079
4238
|
reportedTrips.delete(codeName);
|
|
4080
|
-
|
|
4081
|
-
...
|
|
4239
|
+
state6 = {
|
|
4240
|
+
...state6,
|
|
4082
4241
|
circuitBreakerTrips: restartBreaker.serialize(),
|
|
4083
4242
|
circuitBreakerAutoResumes: Object.fromEntries(autoResumeMarkers.entries())
|
|
4084
4243
|
};
|
|
4085
|
-
send({ type: "state-update", state:
|
|
4244
|
+
send({ type: "state-update", state: state6 });
|
|
4086
4245
|
log(`[auto-resume] agent=${codeName} resumed \u2014 re-trip within backoff window will stay paused (ENG-6088)`);
|
|
4087
4246
|
} else {
|
|
4088
4247
|
autoResumeStandDowns.add(`${codeName}:${trippedAt}`);
|
|
@@ -4238,9 +4397,17 @@ function readMcpHttpServerConfig(projectDir, serverKey) {
|
|
|
4238
4397
|
}
|
|
4239
4398
|
async function runAgentConnectivityProbes(agent, integrations, projectDir) {
|
|
4240
4399
|
if (integrations.length === 0) return;
|
|
4400
|
+
const probeEnv = { ...process.env };
|
|
4401
|
+
try {
|
|
4402
|
+
const envIntPath = join8(projectDir, ".env.integrations");
|
|
4403
|
+
if (existsSync5(envIntPath)) {
|
|
4404
|
+
Object.assign(probeEnv, parseEnvIntegrations(readFileSync9(envIntPath, "utf-8")));
|
|
4405
|
+
}
|
|
4406
|
+
} catch {
|
|
4407
|
+
}
|
|
4241
4408
|
const probeDeps = {
|
|
4242
4409
|
fetchImpl: fetch,
|
|
4243
|
-
runCli: (binary, args) => runCliProbe(binary, args),
|
|
4410
|
+
runCli: (binary, args) => runCliProbe(binary, args, { env: probeEnv }),
|
|
4244
4411
|
mcpProbe: async (target) => {
|
|
4245
4412
|
const cfg = readMcpHttpServerConfig(projectDir, target.serverKey);
|
|
4246
4413
|
if (!cfg) {
|
|
@@ -4452,7 +4619,7 @@ function __setAgentChannelTokensForTest(codeName, tokens) {
|
|
|
4452
4619
|
}
|
|
4453
4620
|
var activeChannels = /* @__PURE__ */ new Map();
|
|
4454
4621
|
var gatewaysStartedThisCycle = /* @__PURE__ */ new Set();
|
|
4455
|
-
var
|
|
4622
|
+
var state6 = {
|
|
4456
4623
|
pid: process.pid,
|
|
4457
4624
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4458
4625
|
lastPollAt: null,
|
|
@@ -4494,7 +4661,7 @@ var cachedMaintenanceWindow = null;
|
|
|
4494
4661
|
var lastVersionCheckAt = 0;
|
|
4495
4662
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
4496
4663
|
var lastResponsivenessProbeAt = 0;
|
|
4497
|
-
var agtCliVersion = true ? "0.27.
|
|
4664
|
+
var agtCliVersion = true ? "0.27.130" : "dev";
|
|
4498
4665
|
function resolveBrewPath(execFileSync4) {
|
|
4499
4666
|
try {
|
|
4500
4667
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -5146,6 +5313,10 @@ async function runEvalClaude(prompt, model) {
|
|
|
5146
5313
|
});
|
|
5147
5314
|
return stdout;
|
|
5148
5315
|
}
|
|
5316
|
+
function memoryExtractionEnabled() {
|
|
5317
|
+
const v = (process.env["AGT_MEMORY_EXTRACTION_ENABLED"] ?? "").trim().toLowerCase();
|
|
5318
|
+
return v === "true" || v === "1" || v === "yes";
|
|
5319
|
+
}
|
|
5149
5320
|
var conversationEvalBackend = null;
|
|
5150
5321
|
function resolveConversationEvalBackend() {
|
|
5151
5322
|
if (conversationEvalBackend) return conversationEvalBackend;
|
|
@@ -5472,10 +5643,10 @@ function isGatewayHung(codeName) {
|
|
|
5472
5643
|
if (!Array.isArray(jobs)) return false;
|
|
5473
5644
|
const now = Date.now();
|
|
5474
5645
|
for (const job of jobs) {
|
|
5475
|
-
const
|
|
5476
|
-
if (!
|
|
5477
|
-
const runStartedAt =
|
|
5478
|
-
const isRunning =
|
|
5646
|
+
const state7 = job.state;
|
|
5647
|
+
if (!state7) continue;
|
|
5648
|
+
const runStartedAt = state7.runStartedAtMs;
|
|
5649
|
+
const isRunning = state7.status === "running" || state7.running === true;
|
|
5479
5650
|
if (isRunning && runStartedAt && now - runStartedAt > GATEWAY_HUNG_TIMEOUT_MS) {
|
|
5480
5651
|
return true;
|
|
5481
5652
|
}
|
|
@@ -5676,7 +5847,7 @@ async function pollCycle() {
|
|
|
5676
5847
|
const now = Date.now();
|
|
5677
5848
|
if (now - lastVersionCheckAt > VERSION_CHECK_INTERVAL_MS) {
|
|
5678
5849
|
try {
|
|
5679
|
-
const firstAgent =
|
|
5850
|
+
const firstAgent = state6.agents[0];
|
|
5680
5851
|
const versionAdapter = firstAgent ? resolveAgentFramework(firstAgent.codeName) : getFramework("openclaw");
|
|
5681
5852
|
if (versionAdapter.getVersion) {
|
|
5682
5853
|
cachedFrameworkVersion = await versionAdapter.getVersion();
|
|
@@ -5687,7 +5858,7 @@ async function pollCycle() {
|
|
|
5687
5858
|
}
|
|
5688
5859
|
try {
|
|
5689
5860
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
5690
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
5861
|
+
const { collectDiagnostics } = await import("../persistent-session-NTO2PO2V.js");
|
|
5691
5862
|
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
5692
5863
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
5693
5864
|
let tailscaleHostname;
|
|
@@ -5720,7 +5891,7 @@ async function pollCycle() {
|
|
|
5720
5891
|
const errId = createHash3("sha256").update(errText).digest("hex").slice(0, 12);
|
|
5721
5892
|
log(`Claude auth detection failed (error_id=${errId})`);
|
|
5722
5893
|
}
|
|
5723
|
-
const hostHasClaudeCode =
|
|
5894
|
+
const hostHasClaudeCode = state6.agents.some(
|
|
5724
5895
|
(a) => agentFrameworkCache.get(a.codeName) === "claude-code"
|
|
5725
5896
|
);
|
|
5726
5897
|
if (hostHasClaudeCode) {
|
|
@@ -5774,12 +5945,12 @@ async function pollCycle() {
|
|
|
5774
5945
|
const {
|
|
5775
5946
|
collectResponsivenessProbes,
|
|
5776
5947
|
getResponsivenessIntervalMs
|
|
5777
|
-
} = await import("../responsiveness-probe-
|
|
5948
|
+
} = await import("../responsiveness-probe-BG7O5UIG.js");
|
|
5778
5949
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
5779
5950
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
5780
5951
|
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
5781
5952
|
if (probeCodeNames.length > 0) {
|
|
5782
|
-
const { takeAcpxExecFailureCount, creditAcpxExecFailureCount } = await import("../persistent-session-
|
|
5953
|
+
const { takeAcpxExecFailureCount, creditAcpxExecFailureCount } = await import("../persistent-session-NTO2PO2V.js");
|
|
5783
5954
|
const drainedGiveUps = /* @__PURE__ */ new Map();
|
|
5784
5955
|
const drainedAcpxFailures = /* @__PURE__ */ new Map();
|
|
5785
5956
|
const probes = collectResponsivenessProbes(probeCodeNames).map((p) => {
|
|
@@ -5813,7 +5984,7 @@ async function pollCycle() {
|
|
|
5813
5984
|
collectResponsivenessProbes,
|
|
5814
5985
|
livePendingInboundOldestAgeSeconds,
|
|
5815
5986
|
deadLetterPendingInbound
|
|
5816
|
-
} = await import("../responsiveness-probe-
|
|
5987
|
+
} = await import("../responsiveness-probe-BG7O5UIG.js");
|
|
5817
5988
|
const wedgeNow = /* @__PURE__ */ new Date();
|
|
5818
5989
|
const liveAgents = agentState.persistentSessionAgents;
|
|
5819
5990
|
for (const tracked of consecutiveWedgeCycles.keys()) {
|
|
@@ -5933,7 +6104,7 @@ async function pollCycle() {
|
|
|
5933
6104
|
for (const agent of agents) {
|
|
5934
6105
|
const requested = agent.restart_requested_at ?? null;
|
|
5935
6106
|
if (!requested) continue;
|
|
5936
|
-
const prev =
|
|
6107
|
+
const prev = state6.agents.find((a) => a.agentId === agent.agent_id);
|
|
5937
6108
|
const lastProcessed = prev?.lastRestartProcessedAt ?? null;
|
|
5938
6109
|
if (lastProcessed && Date.parse(lastProcessed) >= Date.parse(requested)) continue;
|
|
5939
6110
|
log(`[restart] Dashboard requested restart for '${agent.code_name}' at ${requested}`);
|
|
@@ -5956,7 +6127,7 @@ async function pollCycle() {
|
|
|
5956
6127
|
await processAgent(agent, agentStates);
|
|
5957
6128
|
} catch (err) {
|
|
5958
6129
|
log(`Error processing agent '${agent.code_name}': ${err.message}`);
|
|
5959
|
-
const existing =
|
|
6130
|
+
const existing = state6.agents.find((a) => a.agentId === agent.agent_id);
|
|
5960
6131
|
if (existing) {
|
|
5961
6132
|
agentStates.push(existing);
|
|
5962
6133
|
} else {
|
|
@@ -5982,12 +6153,12 @@ async function pollCycle() {
|
|
|
5982
6153
|
void maybeReportActivityCache({ api, log });
|
|
5983
6154
|
const restartAckStateChanged = applyRestartAcks({
|
|
5984
6155
|
agentStates,
|
|
5985
|
-
priorAgents:
|
|
6156
|
+
priorAgents: state6.agents,
|
|
5986
6157
|
restartAcks
|
|
5987
6158
|
});
|
|
5988
6159
|
if (restartAckStateChanged) {
|
|
5989
6160
|
try {
|
|
5990
|
-
const ackedState = { ...
|
|
6161
|
+
const ackedState = { ...state6, agents: agentStates };
|
|
5991
6162
|
atomicWriteFileSync(getStateFile(), JSON.stringify(ackedState, null, 2));
|
|
5992
6163
|
} catch (err) {
|
|
5993
6164
|
log(`[restart] failed to persist ack immediately: ${err.message}`);
|
|
@@ -6005,7 +6176,7 @@ async function pollCycle() {
|
|
|
6005
6176
|
} catch {
|
|
6006
6177
|
}
|
|
6007
6178
|
const currentIds = new Set(agents.map((a) => a.agent_id));
|
|
6008
|
-
for (const prev of
|
|
6179
|
+
for (const prev of state6.agents) {
|
|
6009
6180
|
if (!currentIds.has(prev.agentId)) {
|
|
6010
6181
|
log(`Agent '${prev.codeName}' removed from host (deleted or unassigned)`);
|
|
6011
6182
|
const adapter = resolveAgentFramework(prev.codeName);
|
|
@@ -6146,10 +6317,10 @@ async function pollCycle() {
|
|
|
6146
6317
|
}
|
|
6147
6318
|
} catch {
|
|
6148
6319
|
}
|
|
6149
|
-
|
|
6150
|
-
...
|
|
6320
|
+
state6 = {
|
|
6321
|
+
...state6,
|
|
6151
6322
|
lastPollAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6152
|
-
pollCount:
|
|
6323
|
+
pollCount: state6.pollCount + 1,
|
|
6153
6324
|
agents: agentStates,
|
|
6154
6325
|
// ENG-5441: serialise trip state on every poll so manager restarts
|
|
6155
6326
|
// never silently clear a tripped breaker. Cheap — only tripped
|
|
@@ -6163,9 +6334,9 @@ async function pollCycle() {
|
|
|
6163
6334
|
consecutivePollFailures = 0;
|
|
6164
6335
|
}
|
|
6165
6336
|
verifyPendingRestarts(Date.now());
|
|
6166
|
-
send({ type: "state-update", state:
|
|
6337
|
+
send({ type: "state-update", state: state6 });
|
|
6167
6338
|
} catch (err) {
|
|
6168
|
-
|
|
6339
|
+
state6.errorCount++;
|
|
6169
6340
|
const message = err.message;
|
|
6170
6341
|
log(`Poll error: ${message}`);
|
|
6171
6342
|
send({ type: "error", message });
|
|
@@ -6216,6 +6387,15 @@ async function processAgent(agent, agentStates) {
|
|
|
6216
6387
|
agentId: agent.agent_id,
|
|
6217
6388
|
log
|
|
6218
6389
|
});
|
|
6390
|
+
if (memoryExtractionEnabled()) {
|
|
6391
|
+
void maybeExtractMemories({
|
|
6392
|
+
api,
|
|
6393
|
+
backend: resolveConversationEvalBackend(),
|
|
6394
|
+
codeName: agent.code_name,
|
|
6395
|
+
agentId: agent.agent_id,
|
|
6396
|
+
log
|
|
6397
|
+
});
|
|
6398
|
+
}
|
|
6219
6399
|
}
|
|
6220
6400
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6221
6401
|
const adapter = resolveAgentFramework(agent.code_name);
|
|
@@ -6340,11 +6520,11 @@ async function processAgent(agent, agentStates) {
|
|
|
6340
6520
|
const marker = autoResumeMarkers.get(agent.code_name);
|
|
6341
6521
|
const isSelfResume = marker !== void 0 && Date.now() - marker.autoResumedAt < AUTO_RESUME_SELF_WINDOW_MS;
|
|
6342
6522
|
if (!isSelfResume && autoResumeMarkers.delete(agent.code_name)) {
|
|
6343
|
-
|
|
6344
|
-
...
|
|
6523
|
+
state6 = {
|
|
6524
|
+
...state6,
|
|
6345
6525
|
circuitBreakerAutoResumes: Object.fromEntries(autoResumeMarkers.entries())
|
|
6346
6526
|
};
|
|
6347
|
-
send({ type: "state-update", state:
|
|
6527
|
+
send({ type: "state-update", state: state6 });
|
|
6348
6528
|
log(`[auto-resume] Cleared auto-resume marker for '${agent.code_name}' on operator resume \u2014 credit re-armed (ENG-6088)`);
|
|
6349
6529
|
}
|
|
6350
6530
|
}
|
|
@@ -6375,7 +6555,7 @@ async function processAgent(agent, agentStates) {
|
|
|
6375
6555
|
});
|
|
6376
6556
|
} catch (err) {
|
|
6377
6557
|
log(`Refresh failed for '${agent.code_name}': ${err.message}`);
|
|
6378
|
-
const existing =
|
|
6558
|
+
const existing = state6.agents.find((a) => a.agentId === agent.agent_id);
|
|
6379
6559
|
agentStates.push(existing ?? {
|
|
6380
6560
|
agentId: agent.agent_id,
|
|
6381
6561
|
codeName: agent.code_name,
|
|
@@ -6439,7 +6619,7 @@ async function processAgent(agent, agentStates) {
|
|
|
6439
6619
|
const charterVersion = refreshData.charter.version;
|
|
6440
6620
|
const toolsVersion = refreshData.tools.version;
|
|
6441
6621
|
const known = agentState.knownVersions.get(agent.agent_id);
|
|
6442
|
-
let lastProvisionAt =
|
|
6622
|
+
let lastProvisionAt = state6.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
|
|
6443
6623
|
const quarantinedChannels = channelQuarantineStore().getQuarantinedKeys(agent.code_name);
|
|
6444
6624
|
const currentChannelIds = setWithout(
|
|
6445
6625
|
launchableChannelIds(refreshData.channel_configs),
|
|
@@ -7003,7 +7183,7 @@ async function processAgent(agent, agentStates) {
|
|
|
7003
7183
|
log(`Failed to provision direct-chat channel for '${agent.code_name}': ${err.message}`);
|
|
7004
7184
|
}
|
|
7005
7185
|
}
|
|
7006
|
-
let lastSecretsProvisionAt =
|
|
7186
|
+
let lastSecretsProvisionAt = state6.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
|
|
7007
7187
|
let secretsHash = agentState.knownSecretsHashes.get(agent.agent_id) ?? null;
|
|
7008
7188
|
try {
|
|
7009
7189
|
const secretsData = await api.post("/host/secrets", { agent_id: agent.agent_id });
|
|
@@ -7996,19 +8176,19 @@ function clearStaleCronRunState(jobsPath) {
|
|
|
7996
8176
|
let changed = false;
|
|
7997
8177
|
const now = Date.now();
|
|
7998
8178
|
for (const job of jobs) {
|
|
7999
|
-
const
|
|
8000
|
-
if (!
|
|
8001
|
-
const runStartedAt =
|
|
8002
|
-
const isRunning =
|
|
8179
|
+
const state7 = job.state;
|
|
8180
|
+
if (!state7) continue;
|
|
8181
|
+
const runStartedAt = state7.runningAtMs ?? state7.runStartedAtMs;
|
|
8182
|
+
const isRunning = state7.running === true || state7.status === "running";
|
|
8003
8183
|
if (isRunning && runStartedAt && now - runStartedAt > STALE_RUN_TIMEOUT_MS) {
|
|
8004
|
-
|
|
8005
|
-
delete
|
|
8006
|
-
delete
|
|
8007
|
-
delete
|
|
8184
|
+
state7.running = false;
|
|
8185
|
+
delete state7.status;
|
|
8186
|
+
delete state7.runStartedAtMs;
|
|
8187
|
+
delete state7.currentRunId;
|
|
8008
8188
|
changed = true;
|
|
8009
8189
|
log(`Cleared stale running state for cron job '${job.name}' (stuck for ${Math.round((now - runStartedAt) / 6e4)}min)`);
|
|
8010
8190
|
} else if (isRunning && !runStartedAt) {
|
|
8011
|
-
|
|
8191
|
+
state7.running = false;
|
|
8012
8192
|
changed = true;
|
|
8013
8193
|
log(`Cleared stale running state for cron job '${job.name}' (no start timestamp)`);
|
|
8014
8194
|
}
|
|
@@ -8095,16 +8275,16 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
8095
8275
|
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
8096
8276
|
if (combinedHash !== prevHash) {
|
|
8097
8277
|
const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
|
|
8098
|
-
const
|
|
8099
|
-
claudeSchedulerStates.set(codeName,
|
|
8278
|
+
const state8 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
|
|
8279
|
+
claudeSchedulerStates.set(codeName, state8);
|
|
8100
8280
|
agentState.knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
8101
8281
|
log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
|
|
8102
8282
|
}
|
|
8103
8283
|
if (!claudeSchedulerStates.has(codeName)) {
|
|
8104
8284
|
claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
|
|
8105
8285
|
}
|
|
8106
|
-
const
|
|
8107
|
-
const ready = getReadyTasks(
|
|
8286
|
+
const state7 = claudeSchedulerStates.get(codeName);
|
|
8287
|
+
const ready = getReadyTasks(state7, inFlightClaudeTasks);
|
|
8108
8288
|
if (ready.length === 0) return;
|
|
8109
8289
|
for (const task of ready) {
|
|
8110
8290
|
if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;
|
|
@@ -8264,8 +8444,8 @@ async function deliverScheduledCardResult(codeName, agentId, cardId) {
|
|
|
8264
8444
|
markScheduledCardDeliveryComplete(cardId);
|
|
8265
8445
|
return "terminal";
|
|
8266
8446
|
}
|
|
8267
|
-
const
|
|
8268
|
-
const task =
|
|
8447
|
+
const state7 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
|
|
8448
|
+
const task = state7.tasks[card.source_ref];
|
|
8269
8449
|
if (!task) {
|
|
8270
8450
|
log(`[scheduled-kanban] delivery: no scheduler task for source_ref=${card.source_ref} on '${codeName}' \u2014 skipping`);
|
|
8271
8451
|
markScheduledCardDeliveryComplete(cardId);
|
|
@@ -8828,9 +9008,9 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
|
|
|
8828
9008
|
} else if (!claudeSchedulerStates.has(codeName)) {
|
|
8829
9009
|
claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
|
|
8830
9010
|
}
|
|
8831
|
-
const
|
|
8832
|
-
if (
|
|
8833
|
-
const ready = getReadyTasks(
|
|
9011
|
+
const state7 = claudeSchedulerStates.get(codeName);
|
|
9012
|
+
if (state7) {
|
|
9013
|
+
const ready = getReadyTasks(state7, inFlightClaudeTasks);
|
|
8834
9014
|
if (ready.length > 0) {
|
|
8835
9015
|
log(`[persistent-session] ${ready.length} ready task(s) for '${codeName}': ${ready.map((t) => `${t.name}(next=${t.nextFireAt ? new Date(t.nextFireAt).toISOString() : "null"})`).join(", ")}`);
|
|
8836
9016
|
}
|
|
@@ -10310,7 +10490,7 @@ async function processClaudePairSessions(agents) {
|
|
|
10310
10490
|
killPairSession,
|
|
10311
10491
|
pairTmuxSession,
|
|
10312
10492
|
finalizeClaudePairOnboarding
|
|
10313
|
-
} = await import("../claude-pair-runtime-
|
|
10493
|
+
} = await import("../claude-pair-runtime-GWZWHISO.js");
|
|
10314
10494
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
10315
10495
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
10316
10496
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -10928,8 +11108,8 @@ function startManager(opts) {
|
|
|
10928
11108
|
const raw = readFileSync9(stateFile, "utf-8");
|
|
10929
11109
|
const parsed = JSON.parse(raw);
|
|
10930
11110
|
if (Array.isArray(parsed.agents)) {
|
|
10931
|
-
|
|
10932
|
-
log(`[startup] rehydrated ${
|
|
11111
|
+
state6.agents = parsed.agents;
|
|
11112
|
+
log(`[startup] rehydrated ${state6.agents.length} agent state(s) from ${stateFile}`);
|
|
10933
11113
|
}
|
|
10934
11114
|
if (parsed.circuitBreakerTrips && typeof parsed.circuitBreakerTrips === "object") {
|
|
10935
11115
|
restartBreaker.hydrate(parsed.circuitBreakerTrips);
|