@integrity-labs/agt-cli 0.28.442 → 0.28.443
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-XMJ5VMWV.js → chunk-IQX7TMYZ.js} +153 -9
- package/dist/chunk-IQX7TMYZ.js.map +1 -0
- package/dist/{chunk-JIZ6Z6EX.js → chunk-X2LHWP6E.js} +3 -3
- package/dist/{claude-pair-runtime-G4M27XXA.js → claude-pair-runtime-J3BEIXWL.js} +2 -2
- package/dist/lib/manager-worker.js +35 -49
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/direct-chat-channel.js +438 -32
- package/dist/mcp/origami.js +35 -0
- package/dist/mcp/slack-channel.js +35 -0
- package/dist/mcp/telegram-channel.js +35 -0
- package/dist/{persistent-session-VMWQYV5B.js → persistent-session-6SCIPYQI.js} +2 -2
- package/dist/{responsiveness-probe-WMJEL7IZ.js → responsiveness-probe-WHDWK62P.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-XMJ5VMWV.js.map +0 -1
- /package/dist/{chunk-JIZ6Z6EX.js.map → chunk-X2LHWP6E.js.map} +0 -0
- /package/dist/{claude-pair-runtime-G4M27XXA.js.map → claude-pair-runtime-J3BEIXWL.js.map} +0 -0
- /package/dist/{persistent-session-VMWQYV5B.js.map → persistent-session-6SCIPYQI.js.map} +0 -0
- /package/dist/{responsiveness-probe-WMJEL7IZ.js.map → responsiveness-probe-WHDWK62P.js.map} +0 -0
|
@@ -18867,7 +18867,7 @@ var require_filters = __commonJS({
|
|
|
18867
18867
|
return r.copySafeness(str, res);
|
|
18868
18868
|
}
|
|
18869
18869
|
_exports.indent = indent;
|
|
18870
|
-
function
|
|
18870
|
+
function join14(arr, del, attr) {
|
|
18871
18871
|
del = del || "";
|
|
18872
18872
|
if (attr) {
|
|
18873
18873
|
arr = lib.map(arr, function(v) {
|
|
@@ -18876,7 +18876,7 @@ var require_filters = __commonJS({
|
|
|
18876
18876
|
}
|
|
18877
18877
|
return arr.join(del);
|
|
18878
18878
|
}
|
|
18879
|
-
_exports.join =
|
|
18879
|
+
_exports.join = join14;
|
|
18880
18880
|
function last(arr) {
|
|
18881
18881
|
return arr[arr.length - 1];
|
|
18882
18882
|
}
|
|
@@ -30087,6 +30087,40 @@ function resolveHostBooleanFlag(opts) {
|
|
|
30087
30087
|
if (cached2 !== void 0) return cached2;
|
|
30088
30088
|
return opts.defaultValue;
|
|
30089
30089
|
}
|
|
30090
|
+
var USAGE_LIMIT_REACTIVE_FLAG_KEY = "usage-limit-reactive-notice";
|
|
30091
|
+
function parseUsageLimitReactiveMode(raw) {
|
|
30092
|
+
if (raw === void 0) return void 0;
|
|
30093
|
+
const v = raw.trim().toLowerCase();
|
|
30094
|
+
if (v === "") return void 0;
|
|
30095
|
+
if (v === "off" || v === "shadow" || v === "enforce") return v;
|
|
30096
|
+
const b = envBoolean(raw);
|
|
30097
|
+
if (b === true) return "enforce";
|
|
30098
|
+
if (b === false) return "off";
|
|
30099
|
+
return void 0;
|
|
30100
|
+
}
|
|
30101
|
+
function cachedUsageLimitReactiveMode(path) {
|
|
30102
|
+
try {
|
|
30103
|
+
if (!existsSync4(path)) return void 0;
|
|
30104
|
+
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
30105
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
30106
|
+
const flags = parsed.flags;
|
|
30107
|
+
if (!flags || typeof flags !== "object") return void 0;
|
|
30108
|
+
const value = flags[USAGE_LIMIT_REACTIVE_FLAG_KEY];
|
|
30109
|
+
if (typeof value === "string") return parseUsageLimitReactiveMode(value);
|
|
30110
|
+
if (typeof value === "boolean") return value ? "enforce" : "off";
|
|
30111
|
+
return void 0;
|
|
30112
|
+
} catch {
|
|
30113
|
+
return void 0;
|
|
30114
|
+
}
|
|
30115
|
+
}
|
|
30116
|
+
function resolveUsageLimitReactiveMode(opts) {
|
|
30117
|
+
const env2 = opts?.env ?? process.env;
|
|
30118
|
+
const modeOverride = parseUsageLimitReactiveMode(env2["AGT_USAGE_LIMIT_REACTIVE_MODE"]);
|
|
30119
|
+
if (modeOverride !== void 0) return modeOverride;
|
|
30120
|
+
const cached2 = cachedUsageLimitReactiveMode(opts?.cachePath ?? defaultFlagsCachePath());
|
|
30121
|
+
if (cached2 !== void 0) return cached2;
|
|
30122
|
+
return "off";
|
|
30123
|
+
}
|
|
30090
30124
|
|
|
30091
30125
|
// src/ack-reaction.ts
|
|
30092
30126
|
var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
@@ -30399,19 +30433,19 @@ function readLockHolder(path) {
|
|
|
30399
30433
|
}
|
|
30400
30434
|
|
|
30401
30435
|
// src/direct-chat-channel.ts
|
|
30402
|
-
import { homedir as
|
|
30403
|
-
import { join as
|
|
30436
|
+
import { homedir as homedir5 } from "os";
|
|
30437
|
+
import { join as join13 } from "path";
|
|
30404
30438
|
import { randomUUID } from "crypto";
|
|
30405
30439
|
import {
|
|
30406
30440
|
watch,
|
|
30407
30441
|
mkdirSync as mkdirSync5,
|
|
30408
30442
|
writeFileSync as writeFileSync6,
|
|
30409
|
-
readFileSync as
|
|
30410
|
-
readdirSync as
|
|
30443
|
+
readFileSync as readFileSync12,
|
|
30444
|
+
readdirSync as readdirSync5,
|
|
30411
30445
|
existsSync as existsSync6,
|
|
30412
30446
|
renameSync as renameSync5,
|
|
30413
30447
|
unlinkSync as unlinkSync4,
|
|
30414
|
-
statSync as
|
|
30448
|
+
statSync as statSync3,
|
|
30415
30449
|
createWriteStream
|
|
30416
30450
|
} from "fs";
|
|
30417
30451
|
|
|
@@ -34165,7 +34199,113 @@ var BANNER_PATTERNS = [
|
|
|
34165
34199
|
// pct=100.
|
|
34166
34200
|
new RegExp(`${SUBJECT}hit\\s+your\\s+(?:[a-z0-9-]+\\s+)?limit${SEP}resets\\s+(${RESET_DATE})`, "i")
|
|
34167
34201
|
];
|
|
34202
|
+
function parseUsageBanner(text, now = /* @__PURE__ */ new Date()) {
|
|
34203
|
+
let bestIndex = -1;
|
|
34204
|
+
let best = null;
|
|
34205
|
+
for (let i = 0; i < BANNER_PATTERNS.length; i++) {
|
|
34206
|
+
const pattern = new RegExp(BANNER_PATTERNS[i].source, "gi");
|
|
34207
|
+
let match;
|
|
34208
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
34209
|
+
if (match.index === pattern.lastIndex)
|
|
34210
|
+
pattern.lastIndex++;
|
|
34211
|
+
let pct;
|
|
34212
|
+
let resetStr;
|
|
34213
|
+
if (i === 0) {
|
|
34214
|
+
pct = Number.parseInt(match[1], 10);
|
|
34215
|
+
resetStr = match[2];
|
|
34216
|
+
} else {
|
|
34217
|
+
pct = 100;
|
|
34218
|
+
resetStr = match[1];
|
|
34219
|
+
}
|
|
34220
|
+
if (!Number.isFinite(pct) || pct < 0 || pct > 100)
|
|
34221
|
+
continue;
|
|
34222
|
+
const nextChar = text[match.index + match[0].length];
|
|
34223
|
+
if (nextChar !== void 0 && /[A-Za-z0-9]/.test(nextChar))
|
|
34224
|
+
continue;
|
|
34225
|
+
const weekResetsAt = parseResetDateTime(resetStr, now);
|
|
34226
|
+
if (!weekResetsAt)
|
|
34227
|
+
continue;
|
|
34228
|
+
if (match.index >= bestIndex) {
|
|
34229
|
+
bestIndex = match.index;
|
|
34230
|
+
best = { pct, weekResetsAt };
|
|
34231
|
+
}
|
|
34232
|
+
}
|
|
34233
|
+
}
|
|
34234
|
+
return best;
|
|
34235
|
+
}
|
|
34236
|
+
var MONTHS = [
|
|
34237
|
+
"jan",
|
|
34238
|
+
"feb",
|
|
34239
|
+
"mar",
|
|
34240
|
+
"apr",
|
|
34241
|
+
"may",
|
|
34242
|
+
"jun",
|
|
34243
|
+
"jul",
|
|
34244
|
+
"aug",
|
|
34245
|
+
"sep",
|
|
34246
|
+
"oct",
|
|
34247
|
+
"nov",
|
|
34248
|
+
"dec"
|
|
34249
|
+
];
|
|
34250
|
+
var TIME_TAIL = /,\s*(\d{1,2})(?::(\d{2}))?\s*(am|pm)(?:\s*\(?UTC\)?)?\s*$/i;
|
|
34251
|
+
var TIME_ONLY = /^(\d{1,2})(?::(\d{2}))?\s*(am|pm)(?:\s*\(?UTC\)?)?$/i;
|
|
34168
34252
|
var MS_PER_DAY = 24 * 60 * 60 * 1e3;
|
|
34253
|
+
function parseAmPm(hourStr, minStr, ampm) {
|
|
34254
|
+
const rawHour = Number.parseInt(hourStr, 10);
|
|
34255
|
+
if (!Number.isFinite(rawHour) || rawHour < 1 || rawHour > 12)
|
|
34256
|
+
return null;
|
|
34257
|
+
let minute = 0;
|
|
34258
|
+
if (minStr) {
|
|
34259
|
+
minute = Number.parseInt(minStr, 10);
|
|
34260
|
+
if (!Number.isFinite(minute) || minute < 0 || minute > 59)
|
|
34261
|
+
return null;
|
|
34262
|
+
}
|
|
34263
|
+
const isPm = ampm.toLowerCase() === "pm";
|
|
34264
|
+
return { hour: rawHour % 12 + (isPm ? 12 : 0), minute };
|
|
34265
|
+
}
|
|
34266
|
+
function parseResetDateTime(humanDate, now) {
|
|
34267
|
+
const trimmed = humanDate.trim();
|
|
34268
|
+
const timeOnly = trimmed.match(TIME_ONLY);
|
|
34269
|
+
if (timeOnly) {
|
|
34270
|
+
const hm = parseAmPm(timeOnly[1], timeOnly[2], timeOnly[3]);
|
|
34271
|
+
if (!hm)
|
|
34272
|
+
return null;
|
|
34273
|
+
const todayAt = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), hm.hour, hm.minute);
|
|
34274
|
+
return new Date(todayAt <= now.getTime() ? todayAt + MS_PER_DAY : todayAt);
|
|
34275
|
+
}
|
|
34276
|
+
const timeMatch = trimmed.match(TIME_TAIL);
|
|
34277
|
+
const dateOnly = timeMatch ? trimmed.slice(0, timeMatch.index).trim() : trimmed;
|
|
34278
|
+
const parts = dateOnly.split(/\s+/);
|
|
34279
|
+
if (parts.length !== 2)
|
|
34280
|
+
return null;
|
|
34281
|
+
const month = MONTHS.indexOf(parts[0].slice(0, 3).toLowerCase());
|
|
34282
|
+
if (month < 0)
|
|
34283
|
+
return null;
|
|
34284
|
+
const day = Number.parseInt(parts[1], 10);
|
|
34285
|
+
if (!Number.isFinite(day) || day < 1 || day > 31)
|
|
34286
|
+
return null;
|
|
34287
|
+
let hour = 0;
|
|
34288
|
+
let minute = 0;
|
|
34289
|
+
if (timeMatch) {
|
|
34290
|
+
const hm = parseAmPm(timeMatch[1], timeMatch[2], timeMatch[3]);
|
|
34291
|
+
if (!hm)
|
|
34292
|
+
return null;
|
|
34293
|
+
hour = hm.hour;
|
|
34294
|
+
minute = hm.minute;
|
|
34295
|
+
}
|
|
34296
|
+
const baseYear = now.getUTCFullYear();
|
|
34297
|
+
let resolved = null;
|
|
34298
|
+
let bestDelta = Number.POSITIVE_INFINITY;
|
|
34299
|
+
for (const y of [baseYear - 1, baseYear, baseYear + 1]) {
|
|
34300
|
+
const candidate = new Date(Date.UTC(y, month, day, hour, minute));
|
|
34301
|
+
const delta = Math.abs(candidate.getTime() - now.getTime());
|
|
34302
|
+
if (delta < bestDelta) {
|
|
34303
|
+
bestDelta = delta;
|
|
34304
|
+
resolved = candidate;
|
|
34305
|
+
}
|
|
34306
|
+
}
|
|
34307
|
+
return resolved;
|
|
34308
|
+
}
|
|
34169
34309
|
|
|
34170
34310
|
// ../core/dist/claude-code-usage/usage-limit-marker.js
|
|
34171
34311
|
var USAGE_LIMIT_MARKER_FILENAME = "claude-usage-limit.json";
|
|
@@ -34203,6 +34343,109 @@ function buildUsageLimitReplyText(limitedUntil) {
|
|
|
34203
34343
|
return `Your agent has hit its Claude Code usage limit until ${formatUtcClock(limitedUntil)}. It'll pick back up once the limit resets \u2014 please try again after then.`;
|
|
34204
34344
|
}
|
|
34205
34345
|
|
|
34346
|
+
// ../core/dist/claude-code-usage/rate-limit-classifier.js
|
|
34347
|
+
var UNKNOWN_RATE_LIMIT = Object.freeze({
|
|
34348
|
+
verdict: "unknown",
|
|
34349
|
+
atMs: null,
|
|
34350
|
+
resetsAt: null,
|
|
34351
|
+
text: null
|
|
34352
|
+
});
|
|
34353
|
+
function contentText(record2) {
|
|
34354
|
+
const candidates = [record2.content];
|
|
34355
|
+
const message = record2.message;
|
|
34356
|
+
if (typeof message === "object" && message !== null) {
|
|
34357
|
+
candidates.push(message.content);
|
|
34358
|
+
}
|
|
34359
|
+
const parts = [];
|
|
34360
|
+
for (const candidate of candidates) {
|
|
34361
|
+
if (typeof candidate === "string") {
|
|
34362
|
+
if (candidate)
|
|
34363
|
+
parts.push(candidate);
|
|
34364
|
+
continue;
|
|
34365
|
+
}
|
|
34366
|
+
if (!Array.isArray(candidate))
|
|
34367
|
+
continue;
|
|
34368
|
+
for (const block of candidate) {
|
|
34369
|
+
if (typeof block === "string") {
|
|
34370
|
+
if (block)
|
|
34371
|
+
parts.push(block);
|
|
34372
|
+
continue;
|
|
34373
|
+
}
|
|
34374
|
+
if (typeof block !== "object" || block === null)
|
|
34375
|
+
continue;
|
|
34376
|
+
const text = block.text;
|
|
34377
|
+
if (typeof text === "string" && text)
|
|
34378
|
+
parts.push(text);
|
|
34379
|
+
}
|
|
34380
|
+
}
|
|
34381
|
+
const joined = parts.join("\n").trim();
|
|
34382
|
+
return joined ? joined : null;
|
|
34383
|
+
}
|
|
34384
|
+
function classifyTranscriptLine(line, startMs, endMs, now) {
|
|
34385
|
+
const trimmed = line.trim();
|
|
34386
|
+
if (!trimmed)
|
|
34387
|
+
return null;
|
|
34388
|
+
let obj;
|
|
34389
|
+
try {
|
|
34390
|
+
obj = JSON.parse(trimmed);
|
|
34391
|
+
} catch {
|
|
34392
|
+
return null;
|
|
34393
|
+
}
|
|
34394
|
+
if (typeof obj !== "object" || obj === null)
|
|
34395
|
+
return null;
|
|
34396
|
+
const record2 = obj;
|
|
34397
|
+
if (record2.type !== "assistant")
|
|
34398
|
+
return null;
|
|
34399
|
+
const ts = record2.timestamp;
|
|
34400
|
+
if (typeof ts !== "string" || !ts)
|
|
34401
|
+
return null;
|
|
34402
|
+
const tsMs = new Date(ts).getTime();
|
|
34403
|
+
if (!Number.isFinite(tsMs) || tsMs < startMs || tsMs > endMs)
|
|
34404
|
+
return null;
|
|
34405
|
+
if (record2.error === "rate_limit" || record2.apiErrorStatus === 429) {
|
|
34406
|
+
const text = contentText(record2);
|
|
34407
|
+
const observation = text ? parseUsageBanner(text, now ?? new Date(endMs)) : null;
|
|
34408
|
+
return { verdict: "capped", atMs: tsMs, resetsAt: observation?.weekResetsAt ?? null, text };
|
|
34409
|
+
}
|
|
34410
|
+
if (record2.isApiErrorMessage === true)
|
|
34411
|
+
return null;
|
|
34412
|
+
const message = record2.message;
|
|
34413
|
+
if (typeof message !== "object" || message === null)
|
|
34414
|
+
return null;
|
|
34415
|
+
const msg = message;
|
|
34416
|
+
if (msg.model === "<synthetic>")
|
|
34417
|
+
return null;
|
|
34418
|
+
const usage = msg.usage;
|
|
34419
|
+
if (typeof usage !== "object" || usage === null)
|
|
34420
|
+
return null;
|
|
34421
|
+
const u = usage;
|
|
34422
|
+
const spent = Number(u.input_tokens ?? 0) + Number(u.output_tokens ?? 0) + Number(u.cache_creation_input_tokens ?? 0) + Number(u.cache_read_input_tokens ?? 0);
|
|
34423
|
+
if (!Number.isFinite(spent) || spent <= 0)
|
|
34424
|
+
return null;
|
|
34425
|
+
return { verdict: "serving", atMs: tsMs, resetsAt: null, text: null };
|
|
34426
|
+
}
|
|
34427
|
+
function pickNewerClassification(current, next) {
|
|
34428
|
+
if (next.verdict === "unknown")
|
|
34429
|
+
return current;
|
|
34430
|
+
if (current.verdict === "unknown")
|
|
34431
|
+
return next;
|
|
34432
|
+
return next.atMs >= current.atMs ? next : current;
|
|
34433
|
+
}
|
|
34434
|
+
function classifyTranscriptRateLimit(jsonl, startMs, endMs, now) {
|
|
34435
|
+
let newest = UNKNOWN_RATE_LIMIT;
|
|
34436
|
+
for (const line of jsonl.split("\n")) {
|
|
34437
|
+
const classified = classifyTranscriptLine(line, startMs, endMs, now);
|
|
34438
|
+
if (classified)
|
|
34439
|
+
newest = pickNewerClassification(newest, classified);
|
|
34440
|
+
}
|
|
34441
|
+
return newest;
|
|
34442
|
+
}
|
|
34443
|
+
|
|
34444
|
+
// ../core/dist/claude-code-usage/transcript-location.js
|
|
34445
|
+
function encodeClaudeProjectPath(projectDir) {
|
|
34446
|
+
return "-" + projectDir.replace(/^\//, "").replace(/[/.]/g, "-");
|
|
34447
|
+
}
|
|
34448
|
+
|
|
34206
34449
|
// ../core/dist/account-enforcement/marker.js
|
|
34207
34450
|
var ACCOUNT_ENFORCEMENT_MARKER_FILENAME = "account-enforcement.json";
|
|
34208
34451
|
var ACCOUNT_ENFORCEMENT_MARKER_VERSION = 1;
|
|
@@ -34847,6 +35090,33 @@ var FLAG_REGISTRY = [
|
|
|
34847
35090
|
// projectDefinition, so setting it does not roll FLAGS_SCHEMA_VERSION.
|
|
34848
35091
|
since: "0.28.421"
|
|
34849
35092
|
},
|
|
35093
|
+
{
|
|
35094
|
+
key: "usage-limit-reactive-notice",
|
|
35095
|
+
description: "Report a Claude Code usage cap REACTIVELY instead of predicting it (ENG-8201). Today the manager guesses from the agent transcript that the next turn will be refused, writes a marker, and every channel MCP refuses to dispatch on the strength of that guess - so a wrong guess is a swallowed message, and because the notice is throttled per (channel, sender) while the DROP is not, the usual symptom is total silence rather than a wrong reply. A refused turn actually costs nothing (rejected in under a second, zero tokens) and Claude Code records it with the reset time in it, so there is no need to guess: dispatch, and report the refusal if one comes back. off = today behaviour (pre-dispatch marker gate, no watcher). shadow = still gate on the marker, but ALSO watch dispatched messages and log the refusal that would have been reported - measures the true-positive rate with no user-visible change. enforce = stop reading the marker before dispatch; every admitted human message reaches the agent and a refusal is answered in-thread with the reset time from the error itself. Read live from the heartbeat flags-cache (or the env override).",
|
|
35096
|
+
flagType: "enum",
|
|
35097
|
+
allowedValues: ["off", "shadow", "enforce"],
|
|
35098
|
+
// Ships dark: off preserves today's gate byte-for-byte. shadow is a free
|
|
35099
|
+
// local log line (the watch is a transcript read, no model spend), so it is a
|
|
35100
|
+
// cheap soak; enforce changes what reaches the agent, so it is the audited
|
|
35101
|
+
// per-org flip.
|
|
35102
|
+
defaultValue: "off",
|
|
35103
|
+
// Enum override AGT_USAGE_LIMIT_REACTIVE_MODE (off|shadow|enforce), resolved
|
|
35104
|
+
// by resolveUsageLimitReactiveMode in the channel-server bundle.
|
|
35105
|
+
envVar: "AGT_USAGE_LIMIT_REACTIVE_MODE",
|
|
35106
|
+
// enforce sends a message to an agent the host currently believes is capped -
|
|
35107
|
+
// a deliberate availability trade (the refusal is free, but it is still a
|
|
35108
|
+
// dispatch the operator previously suppressed), so flipping toward it is an
|
|
35109
|
+
// audited change (ADR-0022 sensitive-flag confirm).
|
|
35110
|
+
sensitive: true
|
|
35111
|
+
// ENG-8149: `since` is the agt-cli version that first carries
|
|
35112
|
+
// resolveUsageLimitReactiveMode + the MCP watcher. It cannot be known before
|
|
35113
|
+
// this lands (the auto-publish patch-bumps on merge), and an undefined
|
|
35114
|
+
// `since` makes the flip-reach modal claim FULL reach - true for flags that
|
|
35115
|
+
// predate the reach work, wrong for a NEW host-read flag whose reader older
|
|
35116
|
+
// hosts simply do not have. Backfilled by a follow-up commit once the
|
|
35117
|
+
// publishing run reports the version. Excluded from projectDefinition, so
|
|
35118
|
+
// setting it does not roll FLAGS_SCHEMA_VERSION.
|
|
35119
|
+
},
|
|
34850
35120
|
{
|
|
34851
35121
|
key: "slack-hot-thread-guard",
|
|
34852
35122
|
description: "Server-side hot-thread guard on the slack.reply surface (ENG-7462). Prevents an agent posting a NEW top-level Slack message when it meant to reply inside the thread it is already working in - a prompt/memory rule proved insufficient (the agent had the rule and still slipped). When a reply would otherwise post to channel ROOT (no thread_ts / message_ts / inbound_id, no active kanban card) and the agent has a recent active thread in that channel (its last bot-posted thread, from the persisted trackedThreads cache, within a freshness window), the reply is redirected into that thread. proactive:true no longer implies channel root; posting at root becomes a deliberate action (the to_channel_root flag, or the thread_ts:null sentinel). off = guard never runs, replies with no coords root exactly as today (ships dark). shadow = compute + log the would-redirect but STILL post to root (measure the fire rate before acting). enforce = apply the redirect (a soft-block: redirect + inform, never a hard rejection). Read live from the heartbeat flags-cache (or the env override); enforce is a deliberate per-org flip after a shadow soak.",
|
|
@@ -35570,6 +35840,75 @@ function shouldSendAccountWarn(opts) {
|
|
|
35570
35840
|
}).reply;
|
|
35571
35841
|
}
|
|
35572
35842
|
|
|
35843
|
+
// src/rate-limit-watch.ts
|
|
35844
|
+
import { readFileSync as readFileSync11, readdirSync as readdirSync4, statSync as statSync2 } from "fs";
|
|
35845
|
+
import { homedir as homedir4 } from "os";
|
|
35846
|
+
import { join as join12 } from "path";
|
|
35847
|
+
var DEFAULT_WATCH_MS = 5e3;
|
|
35848
|
+
var DEFAULT_POLL_MS = 400;
|
|
35849
|
+
function agentTranscriptDir(opts) {
|
|
35850
|
+
const cwd = opts?.cwd ?? process.cwd();
|
|
35851
|
+
const home = opts?.home ?? homedir4();
|
|
35852
|
+
return join12(home, ".claude", "projects", encodeClaudeProjectPath(cwd));
|
|
35853
|
+
}
|
|
35854
|
+
function classifyTranscriptSince(opts) {
|
|
35855
|
+
const dir = opts.transcriptDir ?? agentTranscriptDir({ cwd: opts.cwd, home: opts.home });
|
|
35856
|
+
let entries;
|
|
35857
|
+
try {
|
|
35858
|
+
entries = readdirSync4(dir);
|
|
35859
|
+
} catch {
|
|
35860
|
+
return UNKNOWN_RATE_LIMIT;
|
|
35861
|
+
}
|
|
35862
|
+
let newest = UNKNOWN_RATE_LIMIT;
|
|
35863
|
+
for (const name of entries) {
|
|
35864
|
+
if (!name.endsWith(".jsonl")) continue;
|
|
35865
|
+
const path = join12(dir, name);
|
|
35866
|
+
try {
|
|
35867
|
+
const st = statSync2(path);
|
|
35868
|
+
if (!st.isFile() || st.mtimeMs < opts.sinceMs) continue;
|
|
35869
|
+
} catch {
|
|
35870
|
+
continue;
|
|
35871
|
+
}
|
|
35872
|
+
let content;
|
|
35873
|
+
try {
|
|
35874
|
+
content = readFileSync11(path, "utf-8");
|
|
35875
|
+
} catch {
|
|
35876
|
+
continue;
|
|
35877
|
+
}
|
|
35878
|
+
newest = pickNewerClassification(
|
|
35879
|
+
newest,
|
|
35880
|
+
classifyTranscriptRateLimit(content, opts.sinceMs, opts.nowMs, new Date(opts.nowMs))
|
|
35881
|
+
);
|
|
35882
|
+
}
|
|
35883
|
+
return newest;
|
|
35884
|
+
}
|
|
35885
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
35886
|
+
async function watchForRateLimitRefusal(opts) {
|
|
35887
|
+
const now = opts.now ?? (() => Date.now());
|
|
35888
|
+
const wait = opts.wait ?? sleep;
|
|
35889
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_WATCH_MS;
|
|
35890
|
+
const pollMs = opts.pollMs ?? DEFAULT_POLL_MS;
|
|
35891
|
+
const deadline = now() + timeoutMs;
|
|
35892
|
+
for (; ; ) {
|
|
35893
|
+
let result;
|
|
35894
|
+
try {
|
|
35895
|
+
result = classifyTranscriptSince({
|
|
35896
|
+
sinceMs: opts.sinceMs,
|
|
35897
|
+
nowMs: now(),
|
|
35898
|
+
transcriptDir: opts.transcriptDir,
|
|
35899
|
+
cwd: opts.cwd,
|
|
35900
|
+
home: opts.home
|
|
35901
|
+
});
|
|
35902
|
+
} catch {
|
|
35903
|
+
return null;
|
|
35904
|
+
}
|
|
35905
|
+
if (result.verdict === "capped") return result;
|
|
35906
|
+
if (result.verdict === "serving") return null;
|
|
35907
|
+
if (now() >= deadline) return null;
|
|
35908
|
+
await wait(pollMs);
|
|
35909
|
+
}
|
|
35910
|
+
}
|
|
35911
|
+
|
|
35573
35912
|
// src/direct-chat-channel.ts
|
|
35574
35913
|
var DIRECT_CHAT_MAINTENANCE_CACHE = /* @__PURE__ */ new Map();
|
|
35575
35914
|
var DIRECT_CHAT_MAINTENANCE_COOLDOWN_MS = (() => {
|
|
@@ -35588,21 +35927,21 @@ var DIRECT_CHAT_ACCOUNT_WARN_COOLDOWN_MS = (() => {
|
|
|
35588
35927
|
var AGT_HOST = process.env.AGT_HOST;
|
|
35589
35928
|
var AGT_API_KEY = process.env.AGT_API_KEY;
|
|
35590
35929
|
var AGT_AGENT_ID = process.env.AGT_AGENT_ID;
|
|
35591
|
-
var DIRECT_CHAT_AGENT_DIR = AGT_AGENT_ID ?
|
|
35930
|
+
var DIRECT_CHAT_AGENT_DIR = AGT_AGENT_ID ? join13(homedir5(), ".augmented", AGT_AGENT_ID) : null;
|
|
35592
35931
|
var INBOUND_ATTACHMENTS_DIR = resolveInboundAttachmentsDir({
|
|
35593
35932
|
codeName: process.env.AGT_AGENT_CODE_NAME,
|
|
35594
35933
|
turnInitiatorFile: process.env.AGT_TURN_INITIATOR_FILE,
|
|
35595
35934
|
agentId: AGT_AGENT_ID,
|
|
35596
|
-
homeDir:
|
|
35935
|
+
homeDir: homedir5()
|
|
35597
35936
|
});
|
|
35598
35937
|
var AGT_AGENT_CODE_NAME = process.env.AGT_AGENT_CODE_NAME;
|
|
35599
35938
|
var directChatStderrLogStream = null;
|
|
35600
35939
|
if (AGT_AGENT_CODE_NAME) {
|
|
35601
35940
|
try {
|
|
35602
|
-
const logDir =
|
|
35941
|
+
const logDir = join13(homedir5(), ".augmented", AGT_AGENT_CODE_NAME);
|
|
35603
35942
|
mkdirSync5(logDir, { recursive: true });
|
|
35604
35943
|
directChatStderrLogStream = createWriteStream(
|
|
35605
|
-
|
|
35944
|
+
join13(logDir, "direct-chat-channel-stderr.log"),
|
|
35606
35945
|
{ flags: "a", mode: 384 }
|
|
35607
35946
|
);
|
|
35608
35947
|
directChatStderrLogStream.on("error", () => {
|
|
@@ -35621,10 +35960,10 @@ if (AGT_AGENT_CODE_NAME) {
|
|
|
35621
35960
|
} catch {
|
|
35622
35961
|
}
|
|
35623
35962
|
}
|
|
35624
|
-
var PROGRESS_HEARTBEAT_PATH = AGT_AGENT_CODE_NAME ?
|
|
35625
|
-
var DIRECT_CHAT_PENDING_INBOUND_DIR = AGT_AGENT_CODE_NAME ?
|
|
35626
|
-
var DIRECT_CHAT_DELIVERY_LEDGER_DIR = AGT_AGENT_CODE_NAME ?
|
|
35627
|
-
var DIRECT_CHAT_CODE_NAME_AGENT_DIR = AGT_AGENT_CODE_NAME ?
|
|
35963
|
+
var PROGRESS_HEARTBEAT_PATH = AGT_AGENT_CODE_NAME ? join13(homedir5(), ".augmented", AGT_AGENT_CODE_NAME, "channel-progress-heartbeat.json") : null;
|
|
35964
|
+
var DIRECT_CHAT_PENDING_INBOUND_DIR = AGT_AGENT_CODE_NAME ? join13(homedir5(), ".augmented", AGT_AGENT_CODE_NAME, "direct-chat-pending-inbound") : null;
|
|
35965
|
+
var DIRECT_CHAT_DELIVERY_LEDGER_DIR = AGT_AGENT_CODE_NAME ? join13(homedir5(), ".augmented", AGT_AGENT_CODE_NAME, ".agt-inbound-delivery-ledger") : null;
|
|
35966
|
+
var DIRECT_CHAT_CODE_NAME_AGENT_DIR = AGT_AGENT_CODE_NAME ? join13(homedir5(), ".augmented", AGT_AGENT_CODE_NAME) : null;
|
|
35628
35967
|
var DIRECT_CHAT_STALE_MARKER_MS = 24 * 60 * 60 * 1e3;
|
|
35629
35968
|
function recordDirectChatDelivery(sessionId, messageIds) {
|
|
35630
35969
|
if (!sessionId) return;
|
|
@@ -35635,8 +35974,8 @@ function recordDirectChatDelivery(sessionId, messageIds) {
|
|
|
35635
35974
|
delivered_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
35636
35975
|
});
|
|
35637
35976
|
}
|
|
35638
|
-
var DIRECT_CHAT_RECOVERY_OUTBOX_DIR = AGT_AGENT_CODE_NAME ?
|
|
35639
|
-
var DIRECT_CHAT_RECOVERY_LEDGER_DIR = AGT_AGENT_CODE_NAME ?
|
|
35977
|
+
var DIRECT_CHAT_RECOVERY_OUTBOX_DIR = AGT_AGENT_CODE_NAME ? join13(homedir5(), ".augmented", AGT_AGENT_CODE_NAME, "direct-chat-recovery-outbox") : null;
|
|
35978
|
+
var DIRECT_CHAT_RECOVERY_LEDGER_DIR = AGT_AGENT_CODE_NAME ? join13(homedir5(), ".augmented", AGT_AGENT_CODE_NAME, ".agt-direct-chat-recovery-ledger") : null;
|
|
35640
35979
|
var progressReceivedAt = /* @__PURE__ */ new Map();
|
|
35641
35980
|
var directChatProgressState = { tracked: null };
|
|
35642
35981
|
var directChatProgressTickRunning = false;
|
|
@@ -35655,7 +35994,7 @@ var directChatKanbanCardClient = createKanbanCardActiveClient({
|
|
|
35655
35994
|
function readProgressHeartbeat() {
|
|
35656
35995
|
if (!PROGRESS_HEARTBEAT_PATH || !existsSync6(PROGRESS_HEARTBEAT_PATH)) return null;
|
|
35657
35996
|
try {
|
|
35658
|
-
return parseProgressHeartbeat(
|
|
35997
|
+
return parseProgressHeartbeat(readFileSync12(PROGRESS_HEARTBEAT_PATH, "utf-8"));
|
|
35659
35998
|
} catch {
|
|
35660
35999
|
return null;
|
|
35661
36000
|
}
|
|
@@ -35664,7 +36003,7 @@ function seedProgressHeartbeat() {
|
|
|
35664
36003
|
if (!PROGRESS_HEARTBEAT_PATH) return;
|
|
35665
36004
|
const tmp = `${PROGRESS_HEARTBEAT_PATH}.${process.pid}.tmp`;
|
|
35666
36005
|
try {
|
|
35667
|
-
mkdirSync5(
|
|
36006
|
+
mkdirSync5(join13(homedir5(), ".augmented", AGT_AGENT_CODE_NAME), { recursive: true });
|
|
35668
36007
|
writeFileSync6(tmp, serializeProgressHeartbeat(SEED_PROGRESS_STEP, Date.now()), { mode: 384 });
|
|
35669
36008
|
renameSync5(tmp, PROGRESS_HEARTBEAT_PATH);
|
|
35670
36009
|
} catch {
|
|
@@ -35785,7 +36124,7 @@ var STREAM_REPLY_FLUSH_MS = (() => {
|
|
|
35785
36124
|
const n = raw ? Number(raw) : NaN;
|
|
35786
36125
|
return Number.isFinite(n) && n >= 0 ? n : 60;
|
|
35787
36126
|
})();
|
|
35788
|
-
var
|
|
36127
|
+
var sleep2 = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
|
|
35789
36128
|
async function apiPost(path, body) {
|
|
35790
36129
|
const token = await getAuthToken();
|
|
35791
36130
|
const res = await fetchWithTimeout(`${AGT_HOST}${path}`, {
|
|
@@ -35856,7 +36195,7 @@ var inboundAttachmentDeps = {
|
|
|
35856
36195
|
},
|
|
35857
36196
|
ensureDir: (dir) => mkdirSync5(dir, { recursive: true }),
|
|
35858
36197
|
writeFile: (path, bytes) => writeFileSync6(path, bytes, { mode: 384 }),
|
|
35859
|
-
joinPath: (...parts) =>
|
|
36198
|
+
joinPath: (...parts) => join13(...parts),
|
|
35860
36199
|
warn: (msg) => process.stderr.write(`${msg}
|
|
35861
36200
|
`)
|
|
35862
36201
|
};
|
|
@@ -36035,11 +36374,11 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
36035
36374
|
recordDirectChatDelivery(session_id, message_ids);
|
|
36036
36375
|
const messageId = data.message_id;
|
|
36037
36376
|
for (let i = 1; i < slices.length; i++) {
|
|
36038
|
-
await
|
|
36377
|
+
await sleep2(STREAM_REPLY_FLUSH_MS);
|
|
36039
36378
|
const isFinal = i === slices.length - 1;
|
|
36040
36379
|
let ok = await postDirectChatUpdate(messageId, session_id, slices[i]);
|
|
36041
36380
|
if (!ok && isFinal) {
|
|
36042
|
-
await
|
|
36381
|
+
await sleep2(STREAM_REPLY_FLUSH_MS);
|
|
36043
36382
|
ok = await postDirectChatUpdate(messageId, session_id, slices[i]);
|
|
36044
36383
|
if (!ok) {
|
|
36045
36384
|
return {
|
|
@@ -36188,7 +36527,7 @@ function scheduleDirectChatBusyAck(sessionId, messageId, arrivedWhileBusy) {
|
|
|
36188
36527
|
let paneLogFreshAgeMs = null;
|
|
36189
36528
|
if (DIRECT_CHAT_CODE_NAME_AGENT_DIR) {
|
|
36190
36529
|
try {
|
|
36191
|
-
const paneMtimeMs =
|
|
36530
|
+
const paneMtimeMs = statSync3(join13(DIRECT_CHAT_CODE_NAME_AGENT_DIR, "pane.log")).mtimeMs;
|
|
36192
36531
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
36193
36532
|
} catch {
|
|
36194
36533
|
}
|
|
@@ -36236,6 +36575,63 @@ function scheduleDirectChatBusyAck(sessionId, messageId, arrivedWhileBusy) {
|
|
|
36236
36575
|
}, thresholdMs);
|
|
36237
36576
|
timer.unref();
|
|
36238
36577
|
}
|
|
36578
|
+
function armUsageLimitWatch(args) {
|
|
36579
|
+
void (async () => {
|
|
36580
|
+
try {
|
|
36581
|
+
const refusal = await watchForRateLimitRefusal({ sinceMs: args.sinceMs });
|
|
36582
|
+
if (!refusal) return;
|
|
36583
|
+
if (!refusal.resetsAt) {
|
|
36584
|
+
process.stderr.write(
|
|
36585
|
+
`direct-chat-channel: [usage-limit-reactive] mode=${args.mode} refusal detected for session=${args.sessionId} but no reset time in it (${refusal.text ?? "no text"}) - no notice
|
|
36586
|
+
`
|
|
36587
|
+
);
|
|
36588
|
+
return;
|
|
36589
|
+
}
|
|
36590
|
+
if (args.mode === "shadow") {
|
|
36591
|
+
process.stderr.write(
|
|
36592
|
+
`direct-chat-channel: [usage-limit-reactive] mode=shadow WOULD notify session=${args.sessionId} message=${args.messageId} resets=${refusal.resetsAt.toISOString()}
|
|
36593
|
+
`
|
|
36594
|
+
);
|
|
36595
|
+
return;
|
|
36596
|
+
}
|
|
36597
|
+
const throttleKey = `${args.sessionId}|usage_limit`;
|
|
36598
|
+
const throttle = decideDeclineReply({
|
|
36599
|
+
cache: DIRECT_CHAT_USAGE_LIMIT_CACHE,
|
|
36600
|
+
key: throttleKey,
|
|
36601
|
+
cooldownMs: DIRECT_CHAT_MAINTENANCE_COOLDOWN_MS,
|
|
36602
|
+
now: Date.now()
|
|
36603
|
+
});
|
|
36604
|
+
const route = throttle.reply ? "/host/direct-chat/reply" : "/host/direct-chat/consume";
|
|
36605
|
+
const body = throttle.reply ? {
|
|
36606
|
+
agent_id: AGT_AGENT_ID,
|
|
36607
|
+
session_id: args.sessionId,
|
|
36608
|
+
content: buildUsageLimitReplyText(refusal.resetsAt),
|
|
36609
|
+
message_ids: [args.messageId]
|
|
36610
|
+
} : { agent_id: AGT_AGENT_ID, session_id: args.sessionId, message_ids: [args.messageId] };
|
|
36611
|
+
const res = await apiPost(route, body);
|
|
36612
|
+
const data = await res.json().catch(() => ({}));
|
|
36613
|
+
if (res.ok && data.error == null) {
|
|
36614
|
+
claimTracker.clear(args.sessionId, [args.messageId]);
|
|
36615
|
+
clearDirectChatPendingMarkersForSession(DIRECT_CHAT_PENDING_INBOUND_DIR, args.sessionId);
|
|
36616
|
+
process.stderr.write(
|
|
36617
|
+
`direct-chat-channel: [usage-limit-reactive] ${throttle.reply ? "reported" : "consumed (notice throttled)"} refusal for session=${args.sessionId} message=${args.messageId} resets=${refusal.resetsAt.toISOString()}
|
|
36618
|
+
`
|
|
36619
|
+
);
|
|
36620
|
+
} else {
|
|
36621
|
+
if (throttle.reply) DIRECT_CHAT_USAGE_LIMIT_CACHE.delete(throttleKey);
|
|
36622
|
+
process.stderr.write(
|
|
36623
|
+
`direct-chat-channel: [usage-limit-reactive] ${throttle.reply ? "notice" : "consume"} failed for session=${args.sessionId}: ${data.error ?? `HTTP ${res.status}`}
|
|
36624
|
+
`
|
|
36625
|
+
);
|
|
36626
|
+
}
|
|
36627
|
+
} catch (err) {
|
|
36628
|
+
process.stderr.write(
|
|
36629
|
+
`direct-chat-channel: [usage-limit-reactive] watch failed for session=${args.sessionId}: ${err.message}
|
|
36630
|
+
`
|
|
36631
|
+
);
|
|
36632
|
+
}
|
|
36633
|
+
})();
|
|
36634
|
+
}
|
|
36239
36635
|
async function pollForMessages(sinceMs) {
|
|
36240
36636
|
try {
|
|
36241
36637
|
const res = await apiPost("/host/direct-chat/poll", {
|
|
@@ -36262,7 +36658,8 @@ async function pollForMessages(sinceMs) {
|
|
|
36262
36658
|
const isNotice = msg.kind === "notice";
|
|
36263
36659
|
const maintenanceActive = !isNotice && isMaintenanceModeActive();
|
|
36264
36660
|
const accountMuted = !isNotice && !maintenanceActive ? readAccountEnforcementLevel({ codeName: AGT_AGENT_CODE_NAME ?? null }) === "mute" : false;
|
|
36265
|
-
const
|
|
36661
|
+
const reactiveMode = resolveUsageLimitReactiveMode();
|
|
36662
|
+
const usageLimitUntil = !isNotice && !maintenanceActive && !accountMuted && reactiveMode !== "enforce" ? readUsageLimitUntil({ codeName: AGT_AGENT_CODE_NAME ?? null }) : null;
|
|
36266
36663
|
if (!isNotice && !maintenanceActive && !accountMuted && !usageLimitUntil) {
|
|
36267
36664
|
markProcessed(msg.id);
|
|
36268
36665
|
claimTracker.track(msg.session_id, msg.id);
|
|
@@ -36380,6 +36777,7 @@ async function pollForMessages(sinceMs) {
|
|
|
36380
36777
|
if (!isNotice && msg.sender_id) {
|
|
36381
36778
|
clearScheduledTurnMarker(DIRECT_CHAT_CODE_NAME_AGENT_DIR);
|
|
36382
36779
|
}
|
|
36780
|
+
const dispatchedAtMs = Date.now();
|
|
36383
36781
|
await mcp.notification({
|
|
36384
36782
|
method: "notifications/claude/channel",
|
|
36385
36783
|
params: {
|
|
@@ -36440,6 +36838,14 @@ async function pollForMessages(sinceMs) {
|
|
|
36440
36838
|
`direct-chat-channel: Injected message ${msg.id} (session=${msg.session_id})
|
|
36441
36839
|
`
|
|
36442
36840
|
);
|
|
36841
|
+
if (!isNotice && reactiveMode !== "off") {
|
|
36842
|
+
armUsageLimitWatch({
|
|
36843
|
+
mode: reactiveMode,
|
|
36844
|
+
sessionId: msg.session_id,
|
|
36845
|
+
messageId: msg.id,
|
|
36846
|
+
sinceMs: dispatchedAtMs
|
|
36847
|
+
});
|
|
36848
|
+
}
|
|
36443
36849
|
}
|
|
36444
36850
|
} catch (err) {
|
|
36445
36851
|
process.stderr.write(
|
|
@@ -36545,8 +36951,8 @@ function sweepAgedDirectChatMarkersNow(thresholdMs) {
|
|
|
36545
36951
|
if (!DIRECT_CHAT_PENDING_INBOUND_DIR) return;
|
|
36546
36952
|
const now = Date.now();
|
|
36547
36953
|
const res = sweepAgedDirectChatMarkers(DIRECT_CHAT_PENDING_INBOUND_DIR, {
|
|
36548
|
-
readdir: (dir) =>
|
|
36549
|
-
readFile: (p2) =>
|
|
36954
|
+
readdir: (dir) => readdirSync5(dir),
|
|
36955
|
+
readFile: (p2) => readFileSync12(p2, "utf8"),
|
|
36550
36956
|
unlink: (p2) => {
|
|
36551
36957
|
if (existsSync6(p2)) unlinkSync4(p2);
|
|
36552
36958
|
},
|
|
@@ -36582,7 +36988,7 @@ function sanitizeRecoveryText(text) {
|
|
|
36582
36988
|
}
|
|
36583
36989
|
function directChatRecoveryDeps() {
|
|
36584
36990
|
return {
|
|
36585
|
-
readFile: (p2) =>
|
|
36991
|
+
readFile: (p2) => readFileSync12(p2, "utf-8"),
|
|
36586
36992
|
renameFile: (from, to) => renameSync5(from, to),
|
|
36587
36993
|
unlinkFile: (p2) => {
|
|
36588
36994
|
if (existsSync6(p2)) unlinkSync4(p2);
|
|
@@ -36595,7 +37001,7 @@ function directChatRecoveryDeps() {
|
|
|
36595
37001
|
if (!DIRECT_CHAT_RECOVERY_LEDGER_DIR) return;
|
|
36596
37002
|
if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return;
|
|
36597
37003
|
try {
|
|
36598
|
-
const p2 =
|
|
37004
|
+
const p2 = join13(DIRECT_CHAT_RECOVERY_LEDGER_DIR, markerName);
|
|
36599
37005
|
if (existsSync6(p2)) unlinkSync4(p2);
|
|
36600
37006
|
} catch {
|
|
36601
37007
|
}
|
|
@@ -36631,7 +37037,7 @@ async function processDirectChatRecoveryOutboxFile(filename) {
|
|
|
36631
37037
|
if (!enabled) return;
|
|
36632
37038
|
directChatRecoveryInFlight.add(filename);
|
|
36633
37039
|
try {
|
|
36634
|
-
const fullPath =
|
|
37040
|
+
const fullPath = join13(DIRECT_CHAT_RECOVERY_OUTBOX_DIR, filename);
|
|
36635
37041
|
await consumeDirectChatRecoveryFile(fullPath, filename, directChatRecoveryDeps());
|
|
36636
37042
|
} catch (err) {
|
|
36637
37043
|
process.stderr.write(
|
|
@@ -36649,7 +37055,7 @@ if (DIRECT_CHAT_RECOVERY_OUTBOX_DIR) {
|
|
|
36649
37055
|
} catch {
|
|
36650
37056
|
}
|
|
36651
37057
|
try {
|
|
36652
|
-
for (const f of
|
|
37058
|
+
for (const f of readdirSync5(DIRECT_CHAT_RECOVERY_OUTBOX_DIR)) {
|
|
36653
37059
|
if (f.endsWith(".json")) void processDirectChatRecoveryOutboxFile(f);
|
|
36654
37060
|
}
|
|
36655
37061
|
} catch {
|
|
@@ -36659,7 +37065,7 @@ if (DIRECT_CHAT_RECOVERY_OUTBOX_DIR) {
|
|
|
36659
37065
|
if (!filename) return;
|
|
36660
37066
|
const name = filename.toString();
|
|
36661
37067
|
if (!name.endsWith(".json")) return;
|
|
36662
|
-
if (existsSync6(
|
|
37068
|
+
if (existsSync6(join13(DIRECT_CHAT_RECOVERY_OUTBOX_DIR, name))) {
|
|
36663
37069
|
void processDirectChatRecoveryOutboxFile(name);
|
|
36664
37070
|
}
|
|
36665
37071
|
});
|