@adhdev/daemon-standalone 0.9.82-rc.343 → 0.9.82-rc.344
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/index.js +617 -338
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/vendor/mcp-server/index.js +15 -4
- package/vendor/mcp-server/index.js.map +1 -1
package/dist/index.js
CHANGED
|
@@ -30036,10 +30036,10 @@ var require_dist3 = __commonJS({
|
|
|
30036
30036
|
}
|
|
30037
30037
|
function getDaemonBuildInfo() {
|
|
30038
30038
|
if (cached2) return cached2;
|
|
30039
|
-
const commit = readInjected(true ? "
|
|
30040
|
-
const commitShort = readInjected(true ? "
|
|
30041
|
-
const version2 = readInjected(true ? "0.9.82-rc.
|
|
30042
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
30039
|
+
const commit = readInjected(true ? "d04317b7eab7aec6a5557cb1991af603c7e5143c" : void 0) ?? "unknown";
|
|
30040
|
+
const commitShort = readInjected(true ? "d04317b7" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
30041
|
+
const version2 = readInjected(true ? "0.9.82-rc.344" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
30042
|
+
const builtAt = readInjected(true ? "2026-06-21T16:38:22.983Z" : void 0);
|
|
30043
30043
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
30044
30044
|
return cached2;
|
|
30045
30045
|
}
|
|
@@ -32279,6 +32279,314 @@ Follow these recovery rules:
|
|
|
32279
32279
|
4. **Always record what happened**: After handling a failure, briefly note the outcome in your report to the user.`;
|
|
32280
32280
|
}
|
|
32281
32281
|
});
|
|
32282
|
+
var fs32;
|
|
32283
|
+
var AsyncBatchWriter;
|
|
32284
|
+
var init_async_batch_writer = __esm2({
|
|
32285
|
+
"src/logging/async-batch-writer.ts"() {
|
|
32286
|
+
"use strict";
|
|
32287
|
+
fs32 = __toESM2(require("fs"));
|
|
32288
|
+
AsyncBatchWriter = class {
|
|
32289
|
+
// Maps filePath -> string buffer
|
|
32290
|
+
static buffers = /* @__PURE__ */ new Map();
|
|
32291
|
+
static writePromises = /* @__PURE__ */ new Map();
|
|
32292
|
+
static flushTimer = null;
|
|
32293
|
+
/**
|
|
32294
|
+
* Queues data to be written to a file asynchronously in a batch.
|
|
32295
|
+
*/
|
|
32296
|
+
static write(filePath, data) {
|
|
32297
|
+
let buf = this.buffers.get(filePath);
|
|
32298
|
+
if (!buf) {
|
|
32299
|
+
buf = [];
|
|
32300
|
+
this.buffers.set(filePath, buf);
|
|
32301
|
+
}
|
|
32302
|
+
buf.push(data);
|
|
32303
|
+
if (!this.flushTimer) {
|
|
32304
|
+
this.flushTimer = setTimeout(() => {
|
|
32305
|
+
this.flushTimer = null;
|
|
32306
|
+
this.flushAll();
|
|
32307
|
+
}, 50);
|
|
32308
|
+
}
|
|
32309
|
+
}
|
|
32310
|
+
static async flushAll() {
|
|
32311
|
+
const entries = Array.from(this.buffers.entries());
|
|
32312
|
+
this.buffers.clear();
|
|
32313
|
+
for (const [filePath, buffer] of entries) {
|
|
32314
|
+
const dataToWrite = buffer.join("");
|
|
32315
|
+
const doWrite = async () => {
|
|
32316
|
+
try {
|
|
32317
|
+
const prevPromise = this.writePromises.get(filePath);
|
|
32318
|
+
if (prevPromise) await prevPromise;
|
|
32319
|
+
await fs32.promises.appendFile(filePath, dataToWrite, { encoding: "utf-8", mode: 384 });
|
|
32320
|
+
} catch {
|
|
32321
|
+
}
|
|
32322
|
+
};
|
|
32323
|
+
const writePromise = doWrite();
|
|
32324
|
+
this.writePromises.set(filePath, writePromise);
|
|
32325
|
+
writePromise.finally(() => {
|
|
32326
|
+
if (this.writePromises.get(filePath) === writePromise) {
|
|
32327
|
+
this.writePromises.delete(filePath);
|
|
32328
|
+
}
|
|
32329
|
+
});
|
|
32330
|
+
}
|
|
32331
|
+
}
|
|
32332
|
+
};
|
|
32333
|
+
}
|
|
32334
|
+
});
|
|
32335
|
+
var logger_exports = {};
|
|
32336
|
+
__export2(logger_exports, {
|
|
32337
|
+
LOG: () => LOG2,
|
|
32338
|
+
LOG_DIR_PATH: () => LOG_DIR_PATH,
|
|
32339
|
+
LOG_PATH: () => LOG_PATH,
|
|
32340
|
+
daemonLog: () => daemonLog,
|
|
32341
|
+
getCurrentDaemonLogPath: () => getCurrentDaemonLogPath,
|
|
32342
|
+
getDaemonLogDir: () => getDaemonLogDir,
|
|
32343
|
+
getLogBufferSize: () => getLogBufferSize,
|
|
32344
|
+
getLogLevel: () => getLogLevel,
|
|
32345
|
+
getLogPath: () => getLogPath,
|
|
32346
|
+
getRecentLogs: () => getRecentLogs,
|
|
32347
|
+
installGlobalInterceptor: () => installGlobalInterceptor,
|
|
32348
|
+
setLogLevel: () => setLogLevel
|
|
32349
|
+
});
|
|
32350
|
+
function setLogLevel(level) {
|
|
32351
|
+
currentLevel = level;
|
|
32352
|
+
daemonLog("Logger", `Log level set to: ${level}`, "info");
|
|
32353
|
+
}
|
|
32354
|
+
function getLogLevel() {
|
|
32355
|
+
return currentLevel;
|
|
32356
|
+
}
|
|
32357
|
+
function getDateStr() {
|
|
32358
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
32359
|
+
}
|
|
32360
|
+
function getDaemonLogDir() {
|
|
32361
|
+
return LOG_DIR;
|
|
32362
|
+
}
|
|
32363
|
+
function getCurrentDaemonLogPath(date5 = /* @__PURE__ */ new Date()) {
|
|
32364
|
+
return path9.join(LOG_DIR, `daemon-${date5.toISOString().slice(0, 10)}.log`);
|
|
32365
|
+
}
|
|
32366
|
+
function checkDateRotation() {
|
|
32367
|
+
const today = getDateStr();
|
|
32368
|
+
if (today !== currentDate) {
|
|
32369
|
+
currentDate = today;
|
|
32370
|
+
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
32371
|
+
cleanOldLogs();
|
|
32372
|
+
}
|
|
32373
|
+
}
|
|
32374
|
+
function cleanOldLogs() {
|
|
32375
|
+
try {
|
|
32376
|
+
const files = fs4.readdirSync(LOG_DIR).filter((f) => f.startsWith("daemon-") && f.endsWith(".log"));
|
|
32377
|
+
const cutoff = /* @__PURE__ */ new Date();
|
|
32378
|
+
cutoff.setDate(cutoff.getDate() - MAX_LOG_DAYS);
|
|
32379
|
+
const cutoffStr = cutoff.toISOString().slice(0, 10);
|
|
32380
|
+
for (const file2 of files) {
|
|
32381
|
+
const dateMatch = file2.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
32382
|
+
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
32383
|
+
try {
|
|
32384
|
+
fs4.unlinkSync(path9.join(LOG_DIR, file2));
|
|
32385
|
+
} catch {
|
|
32386
|
+
}
|
|
32387
|
+
}
|
|
32388
|
+
}
|
|
32389
|
+
} catch {
|
|
32390
|
+
}
|
|
32391
|
+
}
|
|
32392
|
+
function rotateSizeIfNeeded() {
|
|
32393
|
+
try {
|
|
32394
|
+
const stat2 = fs4.statSync(currentLogFile);
|
|
32395
|
+
if (stat2.size > MAX_LOG_SIZE) {
|
|
32396
|
+
const backup = currentLogFile.replace(".log", ".1.log");
|
|
32397
|
+
try {
|
|
32398
|
+
fs4.unlinkSync(backup);
|
|
32399
|
+
} catch {
|
|
32400
|
+
}
|
|
32401
|
+
fs4.renameSync(currentLogFile, backup);
|
|
32402
|
+
}
|
|
32403
|
+
} catch {
|
|
32404
|
+
}
|
|
32405
|
+
}
|
|
32406
|
+
function writeToFile(line) {
|
|
32407
|
+
try {
|
|
32408
|
+
if (++writeCount % 1e3 === 0) {
|
|
32409
|
+
checkDateRotation();
|
|
32410
|
+
rotateSizeIfNeeded();
|
|
32411
|
+
}
|
|
32412
|
+
AsyncBatchWriter.write(currentLogFile, line + "\n");
|
|
32413
|
+
} catch {
|
|
32414
|
+
}
|
|
32415
|
+
}
|
|
32416
|
+
function getRecentLogs(count = 50, minLevel = "info") {
|
|
32417
|
+
const minNum = LEVEL_NUM[minLevel];
|
|
32418
|
+
const filtered = ringBuffer.filter((e) => LEVEL_NUM[e.level] >= minNum);
|
|
32419
|
+
return filtered.slice(-count);
|
|
32420
|
+
}
|
|
32421
|
+
function getLogBufferSize() {
|
|
32422
|
+
return ringBuffer.length;
|
|
32423
|
+
}
|
|
32424
|
+
function ts() {
|
|
32425
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
32426
|
+
}
|
|
32427
|
+
function fullTs() {
|
|
32428
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
32429
|
+
}
|
|
32430
|
+
function daemonLog(category, msg, level = "info") {
|
|
32431
|
+
const shouldOutput = LEVEL_NUM[level] >= LEVEL_NUM[currentLevel];
|
|
32432
|
+
const label = LEVEL_LABEL[level];
|
|
32433
|
+
const line = `[${ts()}] [${label}] [${category}] ${msg}`;
|
|
32434
|
+
if (!shouldOutput) return;
|
|
32435
|
+
writeToFile(line);
|
|
32436
|
+
ringBuffer.push({ ts: Date.now(), level, category, message: msg });
|
|
32437
|
+
if (ringBuffer.length > RING_BUFFER_SIZE) {
|
|
32438
|
+
ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
|
|
32439
|
+
}
|
|
32440
|
+
origConsoleLog(line);
|
|
32441
|
+
}
|
|
32442
|
+
function installGlobalInterceptor() {
|
|
32443
|
+
if (interceptorInstalled) return;
|
|
32444
|
+
interceptorInstalled = true;
|
|
32445
|
+
const stripAnsi4 = (str) => str.replace(/\x1B\[[0-9;]*m/g, "");
|
|
32446
|
+
const isDaemonLogLine = (msg) => /\[(DBG|INF|WRN|ERR)\]/.test(msg);
|
|
32447
|
+
console.log = (...args) => {
|
|
32448
|
+
origConsoleLog(...args);
|
|
32449
|
+
try {
|
|
32450
|
+
const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
32451
|
+
const clean = stripAnsi4(msg);
|
|
32452
|
+
if (isDaemonLogLine(clean)) return;
|
|
32453
|
+
const line = clean.startsWith("[20") ? clean : `[${fullTs()}] ${clean}`;
|
|
32454
|
+
writeToFile(line);
|
|
32455
|
+
const catMatch = clean.match(/\[([^\]]+)\]/);
|
|
32456
|
+
ringBuffer.push({
|
|
32457
|
+
ts: Date.now(),
|
|
32458
|
+
level: "info",
|
|
32459
|
+
category: catMatch?.[1] || "System",
|
|
32460
|
+
message: clean
|
|
32461
|
+
});
|
|
32462
|
+
if (ringBuffer.length > RING_BUFFER_SIZE) {
|
|
32463
|
+
ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
|
|
32464
|
+
}
|
|
32465
|
+
} catch {
|
|
32466
|
+
}
|
|
32467
|
+
};
|
|
32468
|
+
console.error = (...args) => {
|
|
32469
|
+
origConsoleError(...args);
|
|
32470
|
+
try {
|
|
32471
|
+
const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
32472
|
+
const clean = stripAnsi4(msg);
|
|
32473
|
+
if (isDaemonLogLine(clean)) return;
|
|
32474
|
+
const line = `[${fullTs()}] [ERROR] ${clean}`;
|
|
32475
|
+
writeToFile(line);
|
|
32476
|
+
ringBuffer.push({ ts: Date.now(), level: "error", category: "System", message: clean });
|
|
32477
|
+
if (ringBuffer.length > RING_BUFFER_SIZE) {
|
|
32478
|
+
ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
|
|
32479
|
+
}
|
|
32480
|
+
} catch {
|
|
32481
|
+
}
|
|
32482
|
+
};
|
|
32483
|
+
console.warn = (...args) => {
|
|
32484
|
+
origConsoleWarn(...args);
|
|
32485
|
+
try {
|
|
32486
|
+
const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
32487
|
+
const clean = stripAnsi4(msg);
|
|
32488
|
+
if (isDaemonLogLine(clean)) return;
|
|
32489
|
+
const line = `[${fullTs()}] [WARN] ${clean}`;
|
|
32490
|
+
writeToFile(line);
|
|
32491
|
+
ringBuffer.push({ ts: Date.now(), level: "warn", category: "System", message: clean });
|
|
32492
|
+
if (ringBuffer.length > RING_BUFFER_SIZE) {
|
|
32493
|
+
ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
|
|
32494
|
+
}
|
|
32495
|
+
} catch {
|
|
32496
|
+
}
|
|
32497
|
+
};
|
|
32498
|
+
writeToFile(`
|
|
32499
|
+
=== ADHDev Daemon started at ${fullTs()} ===`);
|
|
32500
|
+
writeToFile(`Log file: ${currentLogFile}`);
|
|
32501
|
+
writeToFile(`Log level: ${currentLevel}`);
|
|
32502
|
+
}
|
|
32503
|
+
function getLogPath() {
|
|
32504
|
+
return currentLogFile;
|
|
32505
|
+
}
|
|
32506
|
+
var fs4;
|
|
32507
|
+
var path9;
|
|
32508
|
+
var os32;
|
|
32509
|
+
var LEVEL_NUM;
|
|
32510
|
+
var LEVEL_LABEL;
|
|
32511
|
+
var currentLevel;
|
|
32512
|
+
var LOG_DIR;
|
|
32513
|
+
var MAX_LOG_SIZE;
|
|
32514
|
+
var MAX_LOG_DAYS;
|
|
32515
|
+
var currentDate;
|
|
32516
|
+
var currentLogFile;
|
|
32517
|
+
var writeCount;
|
|
32518
|
+
var RING_BUFFER_SIZE;
|
|
32519
|
+
var ringBuffer;
|
|
32520
|
+
var origConsoleLog;
|
|
32521
|
+
var origConsoleError;
|
|
32522
|
+
var origConsoleWarn;
|
|
32523
|
+
var LOG2;
|
|
32524
|
+
var interceptorInstalled;
|
|
32525
|
+
var LOG_PATH;
|
|
32526
|
+
var LOG_DIR_PATH;
|
|
32527
|
+
var init_logger = __esm2({
|
|
32528
|
+
"src/logging/logger.ts"() {
|
|
32529
|
+
"use strict";
|
|
32530
|
+
fs4 = __toESM2(require("fs"));
|
|
32531
|
+
path9 = __toESM2(require("path"));
|
|
32532
|
+
os32 = __toESM2(require("os"));
|
|
32533
|
+
init_async_batch_writer();
|
|
32534
|
+
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
32535
|
+
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
32536
|
+
currentLevel = "info";
|
|
32537
|
+
LOG_DIR = process.platform === "win32" ? path9.join(process.env.LOCALAPPDATA || process.env.APPDATA || path9.join(os32.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path9.join(os32.homedir(), "Library", "Logs", "adhdev") : path9.join(os32.homedir(), ".local", "share", "adhdev", "logs");
|
|
32538
|
+
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
32539
|
+
MAX_LOG_DAYS = 7;
|
|
32540
|
+
try {
|
|
32541
|
+
fs4.mkdirSync(LOG_DIR, { recursive: true });
|
|
32542
|
+
} catch {
|
|
32543
|
+
}
|
|
32544
|
+
currentDate = getDateStr();
|
|
32545
|
+
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
32546
|
+
cleanOldLogs();
|
|
32547
|
+
try {
|
|
32548
|
+
const oldLog = path9.join(LOG_DIR, "daemon.log");
|
|
32549
|
+
if (fs4.existsSync(oldLog)) {
|
|
32550
|
+
const stat2 = fs4.statSync(oldLog);
|
|
32551
|
+
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
32552
|
+
fs4.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
32553
|
+
}
|
|
32554
|
+
const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
|
|
32555
|
+
if (fs4.existsSync(oldLogBackup)) {
|
|
32556
|
+
fs4.unlinkSync(oldLogBackup);
|
|
32557
|
+
}
|
|
32558
|
+
} catch {
|
|
32559
|
+
}
|
|
32560
|
+
writeCount = 0;
|
|
32561
|
+
RING_BUFFER_SIZE = 200;
|
|
32562
|
+
ringBuffer = [];
|
|
32563
|
+
origConsoleLog = console.log.bind(console);
|
|
32564
|
+
origConsoleError = console.error.bind(console);
|
|
32565
|
+
origConsoleWarn = console.warn.bind(console);
|
|
32566
|
+
LOG2 = {
|
|
32567
|
+
debug: (category, msg) => daemonLog(category, msg, "debug"),
|
|
32568
|
+
info: (category, msg) => daemonLog(category, msg, "info"),
|
|
32569
|
+
warn: (category, msg) => daemonLog(category, msg, "warn"),
|
|
32570
|
+
error: (category, msg) => daemonLog(category, msg, "error"),
|
|
32571
|
+
/**
|
|
32572
|
+
* Create a scoped logger for a specific component.
|
|
32573
|
+
* Category is baked in so callers only pass the message.
|
|
32574
|
+
*/
|
|
32575
|
+
forComponent(category) {
|
|
32576
|
+
return {
|
|
32577
|
+
debug: (msg) => daemonLog(category, msg, "debug"),
|
|
32578
|
+
info: (msg) => daemonLog(category, msg, "info"),
|
|
32579
|
+
warn: (msg) => daemonLog(category, msg, "warn"),
|
|
32580
|
+
error: (msg) => daemonLog(category, msg, "error"),
|
|
32581
|
+
asLogFn: (level = "info") => (msg) => daemonLog(category, msg, level)
|
|
32582
|
+
};
|
|
32583
|
+
}
|
|
32584
|
+
};
|
|
32585
|
+
interceptorInstalled = false;
|
|
32586
|
+
LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
32587
|
+
LOG_DIR_PATH = LOG_DIR;
|
|
32588
|
+
}
|
|
32589
|
+
});
|
|
32282
32590
|
function loadBetterSqlite3() {
|
|
32283
32591
|
if (cached22) return cached22;
|
|
32284
32592
|
const errors = [];
|
|
@@ -33012,314 +33320,6 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
33012
33320
|
ledgerImportDone = /* @__PURE__ */ new Set();
|
|
33013
33321
|
}
|
|
33014
33322
|
});
|
|
33015
|
-
var fs32;
|
|
33016
|
-
var AsyncBatchWriter;
|
|
33017
|
-
var init_async_batch_writer = __esm2({
|
|
33018
|
-
"src/logging/async-batch-writer.ts"() {
|
|
33019
|
-
"use strict";
|
|
33020
|
-
fs32 = __toESM2(require("fs"));
|
|
33021
|
-
AsyncBatchWriter = class {
|
|
33022
|
-
// Maps filePath -> string buffer
|
|
33023
|
-
static buffers = /* @__PURE__ */ new Map();
|
|
33024
|
-
static writePromises = /* @__PURE__ */ new Map();
|
|
33025
|
-
static flushTimer = null;
|
|
33026
|
-
/**
|
|
33027
|
-
* Queues data to be written to a file asynchronously in a batch.
|
|
33028
|
-
*/
|
|
33029
|
-
static write(filePath, data) {
|
|
33030
|
-
let buf = this.buffers.get(filePath);
|
|
33031
|
-
if (!buf) {
|
|
33032
|
-
buf = [];
|
|
33033
|
-
this.buffers.set(filePath, buf);
|
|
33034
|
-
}
|
|
33035
|
-
buf.push(data);
|
|
33036
|
-
if (!this.flushTimer) {
|
|
33037
|
-
this.flushTimer = setTimeout(() => {
|
|
33038
|
-
this.flushTimer = null;
|
|
33039
|
-
this.flushAll();
|
|
33040
|
-
}, 50);
|
|
33041
|
-
}
|
|
33042
|
-
}
|
|
33043
|
-
static async flushAll() {
|
|
33044
|
-
const entries = Array.from(this.buffers.entries());
|
|
33045
|
-
this.buffers.clear();
|
|
33046
|
-
for (const [filePath, buffer] of entries) {
|
|
33047
|
-
const dataToWrite = buffer.join("");
|
|
33048
|
-
const doWrite = async () => {
|
|
33049
|
-
try {
|
|
33050
|
-
const prevPromise = this.writePromises.get(filePath);
|
|
33051
|
-
if (prevPromise) await prevPromise;
|
|
33052
|
-
await fs32.promises.appendFile(filePath, dataToWrite, { encoding: "utf-8", mode: 384 });
|
|
33053
|
-
} catch {
|
|
33054
|
-
}
|
|
33055
|
-
};
|
|
33056
|
-
const writePromise = doWrite();
|
|
33057
|
-
this.writePromises.set(filePath, writePromise);
|
|
33058
|
-
writePromise.finally(() => {
|
|
33059
|
-
if (this.writePromises.get(filePath) === writePromise) {
|
|
33060
|
-
this.writePromises.delete(filePath);
|
|
33061
|
-
}
|
|
33062
|
-
});
|
|
33063
|
-
}
|
|
33064
|
-
}
|
|
33065
|
-
};
|
|
33066
|
-
}
|
|
33067
|
-
});
|
|
33068
|
-
var logger_exports = {};
|
|
33069
|
-
__export2(logger_exports, {
|
|
33070
|
-
LOG: () => LOG2,
|
|
33071
|
-
LOG_DIR_PATH: () => LOG_DIR_PATH,
|
|
33072
|
-
LOG_PATH: () => LOG_PATH,
|
|
33073
|
-
daemonLog: () => daemonLog,
|
|
33074
|
-
getCurrentDaemonLogPath: () => getCurrentDaemonLogPath,
|
|
33075
|
-
getDaemonLogDir: () => getDaemonLogDir,
|
|
33076
|
-
getLogBufferSize: () => getLogBufferSize,
|
|
33077
|
-
getLogLevel: () => getLogLevel,
|
|
33078
|
-
getLogPath: () => getLogPath,
|
|
33079
|
-
getRecentLogs: () => getRecentLogs,
|
|
33080
|
-
installGlobalInterceptor: () => installGlobalInterceptor,
|
|
33081
|
-
setLogLevel: () => setLogLevel
|
|
33082
|
-
});
|
|
33083
|
-
function setLogLevel(level) {
|
|
33084
|
-
currentLevel = level;
|
|
33085
|
-
daemonLog("Logger", `Log level set to: ${level}`, "info");
|
|
33086
|
-
}
|
|
33087
|
-
function getLogLevel() {
|
|
33088
|
-
return currentLevel;
|
|
33089
|
-
}
|
|
33090
|
-
function getDateStr() {
|
|
33091
|
-
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
33092
|
-
}
|
|
33093
|
-
function getDaemonLogDir() {
|
|
33094
|
-
return LOG_DIR;
|
|
33095
|
-
}
|
|
33096
|
-
function getCurrentDaemonLogPath(date5 = /* @__PURE__ */ new Date()) {
|
|
33097
|
-
return path9.join(LOG_DIR, `daemon-${date5.toISOString().slice(0, 10)}.log`);
|
|
33098
|
-
}
|
|
33099
|
-
function checkDateRotation() {
|
|
33100
|
-
const today = getDateStr();
|
|
33101
|
-
if (today !== currentDate) {
|
|
33102
|
-
currentDate = today;
|
|
33103
|
-
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
33104
|
-
cleanOldLogs();
|
|
33105
|
-
}
|
|
33106
|
-
}
|
|
33107
|
-
function cleanOldLogs() {
|
|
33108
|
-
try {
|
|
33109
|
-
const files = fs4.readdirSync(LOG_DIR).filter((f) => f.startsWith("daemon-") && f.endsWith(".log"));
|
|
33110
|
-
const cutoff = /* @__PURE__ */ new Date();
|
|
33111
|
-
cutoff.setDate(cutoff.getDate() - MAX_LOG_DAYS);
|
|
33112
|
-
const cutoffStr = cutoff.toISOString().slice(0, 10);
|
|
33113
|
-
for (const file2 of files) {
|
|
33114
|
-
const dateMatch = file2.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
33115
|
-
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
33116
|
-
try {
|
|
33117
|
-
fs4.unlinkSync(path9.join(LOG_DIR, file2));
|
|
33118
|
-
} catch {
|
|
33119
|
-
}
|
|
33120
|
-
}
|
|
33121
|
-
}
|
|
33122
|
-
} catch {
|
|
33123
|
-
}
|
|
33124
|
-
}
|
|
33125
|
-
function rotateSizeIfNeeded() {
|
|
33126
|
-
try {
|
|
33127
|
-
const stat2 = fs4.statSync(currentLogFile);
|
|
33128
|
-
if (stat2.size > MAX_LOG_SIZE) {
|
|
33129
|
-
const backup = currentLogFile.replace(".log", ".1.log");
|
|
33130
|
-
try {
|
|
33131
|
-
fs4.unlinkSync(backup);
|
|
33132
|
-
} catch {
|
|
33133
|
-
}
|
|
33134
|
-
fs4.renameSync(currentLogFile, backup);
|
|
33135
|
-
}
|
|
33136
|
-
} catch {
|
|
33137
|
-
}
|
|
33138
|
-
}
|
|
33139
|
-
function writeToFile(line) {
|
|
33140
|
-
try {
|
|
33141
|
-
if (++writeCount % 1e3 === 0) {
|
|
33142
|
-
checkDateRotation();
|
|
33143
|
-
rotateSizeIfNeeded();
|
|
33144
|
-
}
|
|
33145
|
-
AsyncBatchWriter.write(currentLogFile, line + "\n");
|
|
33146
|
-
} catch {
|
|
33147
|
-
}
|
|
33148
|
-
}
|
|
33149
|
-
function getRecentLogs(count = 50, minLevel = "info") {
|
|
33150
|
-
const minNum = LEVEL_NUM[minLevel];
|
|
33151
|
-
const filtered = ringBuffer.filter((e) => LEVEL_NUM[e.level] >= minNum);
|
|
33152
|
-
return filtered.slice(-count);
|
|
33153
|
-
}
|
|
33154
|
-
function getLogBufferSize() {
|
|
33155
|
-
return ringBuffer.length;
|
|
33156
|
-
}
|
|
33157
|
-
function ts() {
|
|
33158
|
-
return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
33159
|
-
}
|
|
33160
|
-
function fullTs() {
|
|
33161
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
33162
|
-
}
|
|
33163
|
-
function daemonLog(category, msg, level = "info") {
|
|
33164
|
-
const shouldOutput = LEVEL_NUM[level] >= LEVEL_NUM[currentLevel];
|
|
33165
|
-
const label = LEVEL_LABEL[level];
|
|
33166
|
-
const line = `[${ts()}] [${label}] [${category}] ${msg}`;
|
|
33167
|
-
if (!shouldOutput) return;
|
|
33168
|
-
writeToFile(line);
|
|
33169
|
-
ringBuffer.push({ ts: Date.now(), level, category, message: msg });
|
|
33170
|
-
if (ringBuffer.length > RING_BUFFER_SIZE) {
|
|
33171
|
-
ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
|
|
33172
|
-
}
|
|
33173
|
-
origConsoleLog(line);
|
|
33174
|
-
}
|
|
33175
|
-
function installGlobalInterceptor() {
|
|
33176
|
-
if (interceptorInstalled) return;
|
|
33177
|
-
interceptorInstalled = true;
|
|
33178
|
-
const stripAnsi4 = (str) => str.replace(/\x1B\[[0-9;]*m/g, "");
|
|
33179
|
-
const isDaemonLogLine = (msg) => /\[(DBG|INF|WRN|ERR)\]/.test(msg);
|
|
33180
|
-
console.log = (...args) => {
|
|
33181
|
-
origConsoleLog(...args);
|
|
33182
|
-
try {
|
|
33183
|
-
const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
33184
|
-
const clean = stripAnsi4(msg);
|
|
33185
|
-
if (isDaemonLogLine(clean)) return;
|
|
33186
|
-
const line = clean.startsWith("[20") ? clean : `[${fullTs()}] ${clean}`;
|
|
33187
|
-
writeToFile(line);
|
|
33188
|
-
const catMatch = clean.match(/\[([^\]]+)\]/);
|
|
33189
|
-
ringBuffer.push({
|
|
33190
|
-
ts: Date.now(),
|
|
33191
|
-
level: "info",
|
|
33192
|
-
category: catMatch?.[1] || "System",
|
|
33193
|
-
message: clean
|
|
33194
|
-
});
|
|
33195
|
-
if (ringBuffer.length > RING_BUFFER_SIZE) {
|
|
33196
|
-
ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
|
|
33197
|
-
}
|
|
33198
|
-
} catch {
|
|
33199
|
-
}
|
|
33200
|
-
};
|
|
33201
|
-
console.error = (...args) => {
|
|
33202
|
-
origConsoleError(...args);
|
|
33203
|
-
try {
|
|
33204
|
-
const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
33205
|
-
const clean = stripAnsi4(msg);
|
|
33206
|
-
if (isDaemonLogLine(clean)) return;
|
|
33207
|
-
const line = `[${fullTs()}] [ERROR] ${clean}`;
|
|
33208
|
-
writeToFile(line);
|
|
33209
|
-
ringBuffer.push({ ts: Date.now(), level: "error", category: "System", message: clean });
|
|
33210
|
-
if (ringBuffer.length > RING_BUFFER_SIZE) {
|
|
33211
|
-
ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
|
|
33212
|
-
}
|
|
33213
|
-
} catch {
|
|
33214
|
-
}
|
|
33215
|
-
};
|
|
33216
|
-
console.warn = (...args) => {
|
|
33217
|
-
origConsoleWarn(...args);
|
|
33218
|
-
try {
|
|
33219
|
-
const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
33220
|
-
const clean = stripAnsi4(msg);
|
|
33221
|
-
if (isDaemonLogLine(clean)) return;
|
|
33222
|
-
const line = `[${fullTs()}] [WARN] ${clean}`;
|
|
33223
|
-
writeToFile(line);
|
|
33224
|
-
ringBuffer.push({ ts: Date.now(), level: "warn", category: "System", message: clean });
|
|
33225
|
-
if (ringBuffer.length > RING_BUFFER_SIZE) {
|
|
33226
|
-
ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
|
|
33227
|
-
}
|
|
33228
|
-
} catch {
|
|
33229
|
-
}
|
|
33230
|
-
};
|
|
33231
|
-
writeToFile(`
|
|
33232
|
-
=== ADHDev Daemon started at ${fullTs()} ===`);
|
|
33233
|
-
writeToFile(`Log file: ${currentLogFile}`);
|
|
33234
|
-
writeToFile(`Log level: ${currentLevel}`);
|
|
33235
|
-
}
|
|
33236
|
-
function getLogPath() {
|
|
33237
|
-
return currentLogFile;
|
|
33238
|
-
}
|
|
33239
|
-
var fs4;
|
|
33240
|
-
var path9;
|
|
33241
|
-
var os32;
|
|
33242
|
-
var LEVEL_NUM;
|
|
33243
|
-
var LEVEL_LABEL;
|
|
33244
|
-
var currentLevel;
|
|
33245
|
-
var LOG_DIR;
|
|
33246
|
-
var MAX_LOG_SIZE;
|
|
33247
|
-
var MAX_LOG_DAYS;
|
|
33248
|
-
var currentDate;
|
|
33249
|
-
var currentLogFile;
|
|
33250
|
-
var writeCount;
|
|
33251
|
-
var RING_BUFFER_SIZE;
|
|
33252
|
-
var ringBuffer;
|
|
33253
|
-
var origConsoleLog;
|
|
33254
|
-
var origConsoleError;
|
|
33255
|
-
var origConsoleWarn;
|
|
33256
|
-
var LOG2;
|
|
33257
|
-
var interceptorInstalled;
|
|
33258
|
-
var LOG_PATH;
|
|
33259
|
-
var LOG_DIR_PATH;
|
|
33260
|
-
var init_logger = __esm2({
|
|
33261
|
-
"src/logging/logger.ts"() {
|
|
33262
|
-
"use strict";
|
|
33263
|
-
fs4 = __toESM2(require("fs"));
|
|
33264
|
-
path9 = __toESM2(require("path"));
|
|
33265
|
-
os32 = __toESM2(require("os"));
|
|
33266
|
-
init_async_batch_writer();
|
|
33267
|
-
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
33268
|
-
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
33269
|
-
currentLevel = "info";
|
|
33270
|
-
LOG_DIR = process.platform === "win32" ? path9.join(process.env.LOCALAPPDATA || process.env.APPDATA || path9.join(os32.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path9.join(os32.homedir(), "Library", "Logs", "adhdev") : path9.join(os32.homedir(), ".local", "share", "adhdev", "logs");
|
|
33271
|
-
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
33272
|
-
MAX_LOG_DAYS = 7;
|
|
33273
|
-
try {
|
|
33274
|
-
fs4.mkdirSync(LOG_DIR, { recursive: true });
|
|
33275
|
-
} catch {
|
|
33276
|
-
}
|
|
33277
|
-
currentDate = getDateStr();
|
|
33278
|
-
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
33279
|
-
cleanOldLogs();
|
|
33280
|
-
try {
|
|
33281
|
-
const oldLog = path9.join(LOG_DIR, "daemon.log");
|
|
33282
|
-
if (fs4.existsSync(oldLog)) {
|
|
33283
|
-
const stat2 = fs4.statSync(oldLog);
|
|
33284
|
-
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
33285
|
-
fs4.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
33286
|
-
}
|
|
33287
|
-
const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
|
|
33288
|
-
if (fs4.existsSync(oldLogBackup)) {
|
|
33289
|
-
fs4.unlinkSync(oldLogBackup);
|
|
33290
|
-
}
|
|
33291
|
-
} catch {
|
|
33292
|
-
}
|
|
33293
|
-
writeCount = 0;
|
|
33294
|
-
RING_BUFFER_SIZE = 200;
|
|
33295
|
-
ringBuffer = [];
|
|
33296
|
-
origConsoleLog = console.log.bind(console);
|
|
33297
|
-
origConsoleError = console.error.bind(console);
|
|
33298
|
-
origConsoleWarn = console.warn.bind(console);
|
|
33299
|
-
LOG2 = {
|
|
33300
|
-
debug: (category, msg) => daemonLog(category, msg, "debug"),
|
|
33301
|
-
info: (category, msg) => daemonLog(category, msg, "info"),
|
|
33302
|
-
warn: (category, msg) => daemonLog(category, msg, "warn"),
|
|
33303
|
-
error: (category, msg) => daemonLog(category, msg, "error"),
|
|
33304
|
-
/**
|
|
33305
|
-
* Create a scoped logger for a specific component.
|
|
33306
|
-
* Category is baked in so callers only pass the message.
|
|
33307
|
-
*/
|
|
33308
|
-
forComponent(category) {
|
|
33309
|
-
return {
|
|
33310
|
-
debug: (msg) => daemonLog(category, msg, "debug"),
|
|
33311
|
-
info: (msg) => daemonLog(category, msg, "info"),
|
|
33312
|
-
warn: (msg) => daemonLog(category, msg, "warn"),
|
|
33313
|
-
error: (msg) => daemonLog(category, msg, "error"),
|
|
33314
|
-
asLogFn: (level = "info") => (msg) => daemonLog(category, msg, level)
|
|
33315
|
-
};
|
|
33316
|
-
}
|
|
33317
|
-
};
|
|
33318
|
-
interceptorInstalled = false;
|
|
33319
|
-
LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
33320
|
-
LOG_DIR_PATH = LOG_DIR;
|
|
33321
|
-
}
|
|
33322
|
-
});
|
|
33323
33323
|
var mesh_work_queue_exports = {};
|
|
33324
33324
|
__export2(mesh_work_queue_exports, {
|
|
33325
33325
|
ACTIVE_MESH_QUEUE_STATUSES: () => ACTIVE_MESH_QUEUE_STATUSES,
|
|
@@ -33635,6 +33635,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
33635
33635
|
requiredTags: resolvedRequiredTags,
|
|
33636
33636
|
...dependsOn.length > 0 ? { dependsOn } : {},
|
|
33637
33637
|
...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
|
|
33638
|
+
...typeof opts?.sourceCoordinatorSessionId === "string" && opts.sourceCoordinatorSessionId.trim() ? { sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId.trim() } : {},
|
|
33638
33639
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
33639
33640
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
33640
33641
|
};
|
|
@@ -33992,22 +33993,33 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
33992
33993
|
(0, import_fs5.renameSync)(legacyCompanion, `${nextPath}${suffix}`);
|
|
33993
33994
|
}
|
|
33994
33995
|
}
|
|
33995
|
-
} catch {
|
|
33996
|
+
} catch (err) {
|
|
33997
|
+
if (!loggedMigrationFailure) {
|
|
33998
|
+
loggedMigrationFailure = true;
|
|
33999
|
+
LOG2.warn(
|
|
34000
|
+
"MeshRuntimeStore",
|
|
34001
|
+
`Legacy beads.db\u2192mesh-runtime.db migration failed; using existing DB in-place to avoid data loss: ${err?.message || err}`
|
|
34002
|
+
);
|
|
34003
|
+
}
|
|
34004
|
+
return (0, import_fs5.existsSync)(nextPath) ? nextPath : legacyPath;
|
|
33996
34005
|
}
|
|
33997
34006
|
return nextPath;
|
|
33998
34007
|
}
|
|
33999
34008
|
var import_fs5;
|
|
34000
34009
|
var import_path5;
|
|
34001
34010
|
var DatabaseCtor;
|
|
34011
|
+
var loggedMigrationFailure;
|
|
34002
34012
|
var MeshRuntimeStore;
|
|
34003
34013
|
var init_mesh_runtime_store = __esm2({
|
|
34004
34014
|
"src/mesh/mesh-runtime-store.ts"() {
|
|
34005
34015
|
"use strict";
|
|
34006
34016
|
import_fs5 = require("fs");
|
|
34007
34017
|
import_path5 = require("path");
|
|
34018
|
+
init_logger();
|
|
34008
34019
|
init_load_better_sqlite3();
|
|
34009
34020
|
init_mesh_ledger();
|
|
34010
34021
|
init_mesh_work_queue();
|
|
34022
|
+
loggedMigrationFailure = false;
|
|
34011
34023
|
MeshRuntimeStore = class _MeshRuntimeStore {
|
|
34012
34024
|
static instance;
|
|
34013
34025
|
db;
|
|
@@ -34029,9 +34041,21 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
34029
34041
|
this.db.pragma("busy_timeout = 5000");
|
|
34030
34042
|
this.migrate();
|
|
34031
34043
|
}
|
|
34044
|
+
static loggedGetInstanceFailure = false;
|
|
34032
34045
|
static getInstance() {
|
|
34033
34046
|
if (!this.instance) {
|
|
34034
|
-
|
|
34047
|
+
try {
|
|
34048
|
+
this.instance = new _MeshRuntimeStore(meshRuntimeStorePath());
|
|
34049
|
+
} catch (err) {
|
|
34050
|
+
if (!_MeshRuntimeStore.loggedGetInstanceFailure) {
|
|
34051
|
+
_MeshRuntimeStore.loggedGetInstanceFailure = true;
|
|
34052
|
+
LOG2.warn(
|
|
34053
|
+
"MeshRuntimeStore",
|
|
34054
|
+
`getInstance failed; callers will degrade to JSONL-only: ${err?.message || err}`
|
|
34055
|
+
);
|
|
34056
|
+
}
|
|
34057
|
+
throw err;
|
|
34058
|
+
}
|
|
34035
34059
|
}
|
|
34036
34060
|
return this.instance;
|
|
34037
34061
|
}
|
|
@@ -37622,7 +37646,11 @@ ${rendered}`, "utf-8");
|
|
|
37622
37646
|
if (coordinatorDaemonId && !readNonEmptyString2(settings.meshCoordinatorDaemonId)) {
|
|
37623
37647
|
stamp.meshCoordinatorDaemonId = coordinatorDaemonId;
|
|
37624
37648
|
}
|
|
37625
|
-
|
|
37649
|
+
const coordinatorSessionId = readNonEmptyString2(meshContext.coordinatorSessionId);
|
|
37650
|
+
if (coordinatorSessionId && !readNonEmptyString2(settings.meshCoordinatorSessionId)) {
|
|
37651
|
+
stamp.meshCoordinatorSessionId = coordinatorSessionId;
|
|
37652
|
+
}
|
|
37653
|
+
if ((meshId || nodeId || coordinatorDaemonId || coordinatorSessionId) && settings.launchedByCoordinator !== true) {
|
|
37626
37654
|
stamp.launchedByCoordinator = true;
|
|
37627
37655
|
}
|
|
37628
37656
|
return Object.keys(stamp).length > 0 ? stamp : void 0;
|
|
@@ -37639,10 +37667,13 @@ ${rendered}`, "utf-8");
|
|
|
37639
37667
|
function readWorkerResultMetadata(event) {
|
|
37640
37668
|
return readRecord4(event.workerResult) || readRecord4(event.meshWorkerResult) || readRecord4(event.structuredResult);
|
|
37641
37669
|
}
|
|
37642
|
-
function
|
|
37670
|
+
function readMeshCompletionSummary(metadataEvent) {
|
|
37643
37671
|
const workerResult = readWorkerResultMetadata(metadataEvent);
|
|
37644
37672
|
const resultRecord = readRecord4(metadataEvent.result);
|
|
37645
|
-
|
|
37673
|
+
return readNonEmptyString2(metadataEvent.finalSummary) || readNonEmptyString2(workerResult?.summary) || readNonEmptyString2(workerResult?.finalSummary) || readNonEmptyString2(resultRecord?.summary) || readNonEmptyString2(resultRecord?.finalSummary);
|
|
37674
|
+
}
|
|
37675
|
+
function resolveMeshSurfacedSessionPreview(metadataEvent) {
|
|
37676
|
+
const summaryText = readMeshCompletionSummary(metadataEvent);
|
|
37646
37677
|
if (!summaryText) return void 0;
|
|
37647
37678
|
const truncationSuffix = "...[truncated]";
|
|
37648
37679
|
const preview = summaryText.length > MESH_SURFACED_PREVIEW_MAX_CHARS ? `${summaryText.slice(0, MESH_SURFACED_PREVIEW_MAX_CHARS - truncationSuffix.length)}${truncationSuffix}` : summaryText;
|
|
@@ -37680,7 +37711,18 @@ ${rendered}`, "utf-8");
|
|
|
37680
37711
|
if (args.metadataEvent.source === "no_progress_reconciliation") {
|
|
37681
37712
|
return `[System] ${args.nodeLabel} already has completion evidence${metadata}. The no-progress monitor reconciled the terminal handoff and marked the session complete; wait for the queued completion event/status refresh before doing any manual transcript check.`;
|
|
37682
37713
|
}
|
|
37683
|
-
const
|
|
37714
|
+
const reviewRecommended = args.metadataEvent.reviewRecommended === true;
|
|
37715
|
+
const completionSummary = readMeshCompletionSummary(args.metadataEvent);
|
|
37716
|
+
if (completionSummary) {
|
|
37717
|
+
const truncationSuffix = "\n\u2026[truncated \u2014 call mesh_read_chat once for the full transcript]";
|
|
37718
|
+
const surfaced = completionSummary.length > MESH_COMPLETION_SURFACE_MAX_CHARS ? `${completionSummary.slice(0, MESH_COMPLETION_SURFACE_MAX_CHARS - truncationSuffix.length)}${truncationSuffix}` : completionSummary;
|
|
37719
|
+
const verifyNote = reviewRecommended ? " Completion evidence is insufficient \u2014 verify via git status or provider_session_id before assuming the task is done." : "";
|
|
37720
|
+
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. Its final summary is included below \u2014 read it directly and only call mesh_read_chat if you need the full transcript.${verifyNote}
|
|
37721
|
+
|
|
37722
|
+
--- ${args.nodeLabel} final summary ---
|
|
37723
|
+
${surfaced}`;
|
|
37724
|
+
}
|
|
37725
|
+
const reviewNote = reviewRecommended ? " Completion evidence is insufficient \u2014 verify via git status or provider_session_id before assuming the task is done. Use mesh_read_chat once if needed, but do not poll repeatedly." : " Use mesh_read_chat once to review its final progress, but do not poll repeatedly.";
|
|
37684
37726
|
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path;${reviewNote}`;
|
|
37685
37727
|
}
|
|
37686
37728
|
if (args.event === "agent:waiting_approval") {
|
|
@@ -37789,10 +37831,12 @@ Next step: ${nextStep}`;
|
|
|
37789
37831
|
return "";
|
|
37790
37832
|
}
|
|
37791
37833
|
var MESH_SURFACED_PREVIEW_MAX_CHARS;
|
|
37834
|
+
var MESH_COMPLETION_SURFACE_MAX_CHARS;
|
|
37792
37835
|
var init_mesh_events_utils = __esm2({
|
|
37793
37836
|
"src/mesh/mesh-events-utils.ts"() {
|
|
37794
37837
|
"use strict";
|
|
37795
37838
|
MESH_SURFACED_PREVIEW_MAX_CHARS = 512;
|
|
37839
|
+
MESH_COMPLETION_SURFACE_MAX_CHARS = 4e3;
|
|
37796
37840
|
}
|
|
37797
37841
|
});
|
|
37798
37842
|
function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
|
|
@@ -37948,6 +37992,37 @@ Next step: ${nextStep}`;
|
|
|
37948
37992
|
if ((0, import_fs10.statSync)(path422).size <= MAX_PENDING_EVENTS_BYTES) return;
|
|
37949
37993
|
const lines = (0, import_fs10.readFileSync)(path422, "utf-8").split("\n").filter(Boolean);
|
|
37950
37994
|
if (lines.length <= MAX_PENDING_EVENTS_KEEP) return;
|
|
37995
|
+
const dropped = lines.slice(0, lines.length - MAX_PENDING_EVENTS_KEEP);
|
|
37996
|
+
for (const line of dropped) {
|
|
37997
|
+
let event;
|
|
37998
|
+
try {
|
|
37999
|
+
event = JSON.parse(line);
|
|
38000
|
+
} catch {
|
|
38001
|
+
continue;
|
|
38002
|
+
}
|
|
38003
|
+
if (!event || !event.meshId) continue;
|
|
38004
|
+
const finalSummary = readMeshCompletionSummary(event.metadataEvent || {});
|
|
38005
|
+
if (!readNonEmptyString2(event.coordinatorMessage) && !finalSummary) continue;
|
|
38006
|
+
try {
|
|
38007
|
+
appendLedgerEntry(event.meshId, {
|
|
38008
|
+
kind: "event_held",
|
|
38009
|
+
...event.nodeId ? { nodeId: event.nodeId } : {},
|
|
38010
|
+
payload: {
|
|
38011
|
+
event: event.event,
|
|
38012
|
+
reason: "pending_trim_dropped",
|
|
38013
|
+
recoverable: true,
|
|
38014
|
+
nodeLabel: event.nodeLabel,
|
|
38015
|
+
...event.workspace ? { workspace: event.workspace } : {},
|
|
38016
|
+
targetCoordinatorDaemonId: event.targetCoordinatorDaemonId ?? null,
|
|
38017
|
+
queuedAt: event.queuedAt,
|
|
38018
|
+
...finalSummary ? { finalSummary } : {}
|
|
38019
|
+
}
|
|
38020
|
+
});
|
|
38021
|
+
LOG2.warn("MeshEvents", `Pending-events trim dropping undelivered ${event.event} for mesh ${event.meshId} \u2014 recorded to ledger (recoverable)`);
|
|
38022
|
+
} catch (e) {
|
|
38023
|
+
LOG2.warn("MeshEvents", `Failed to ledger-record trim-dropped ${event.event} for mesh ${event.meshId}: ${e?.message || e}`);
|
|
38024
|
+
}
|
|
38025
|
+
}
|
|
37951
38026
|
(0, import_fs10.writeFileSync)(path422, lines.slice(-MAX_PENDING_EVENTS_KEEP).join("\n") + "\n", "utf-8");
|
|
37952
38027
|
} catch {
|
|
37953
38028
|
}
|
|
@@ -38077,7 +38152,8 @@ Next step: ${nextStep}`;
|
|
|
38077
38152
|
if (event) pushUnique(event);
|
|
38078
38153
|
}
|
|
38079
38154
|
}
|
|
38080
|
-
} catch {
|
|
38155
|
+
} catch (e) {
|
|
38156
|
+
LOG2.warn("MeshEvents", `SQLite pending-event drain failed for mesh ${meshId}; JSONL fallback only: ${e?.message || e}`);
|
|
38081
38157
|
}
|
|
38082
38158
|
const paths = primaryDaemonId ? [getPendingEventsPath(meshId, primaryDaemonId), getPendingEventsPath(meshId)] : [getPendingEventsPath(meshId)];
|
|
38083
38159
|
for (const path422 of paths) {
|
|
@@ -39494,6 +39570,8 @@ Next step: ${nextStep}`;
|
|
|
39494
39570
|
if (node?.daemonId && components.dispatchMeshCommand) {
|
|
39495
39571
|
const isLocalNode = components.cliManager.adapters.has(sessionId);
|
|
39496
39572
|
if (!isLocalNode) {
|
|
39573
|
+
const localDaemonIdForDispatch = readNonEmptyString2(loadConfig2().machineId) || void 0;
|
|
39574
|
+
const sourceCoordinatorSessionId = readNonEmptyString2(task.sourceCoordinatorSessionId) || void 0;
|
|
39497
39575
|
const delivery2 = createSessionDelivery({
|
|
39498
39576
|
meshId,
|
|
39499
39577
|
nodeId,
|
|
@@ -39502,9 +39580,10 @@ Next step: ${nextStep}`;
|
|
|
39502
39580
|
taskId: task.id,
|
|
39503
39581
|
kind: "task",
|
|
39504
39582
|
message: task.message,
|
|
39505
|
-
status: "delivering"
|
|
39583
|
+
status: "delivering",
|
|
39584
|
+
...sourceCoordinatorSessionId ? { sourceCoordinatorSessionId } : {},
|
|
39585
|
+
...localDaemonIdForDispatch ? { sourceCoordinatorDaemonId: localDaemonIdForDispatch } : {}
|
|
39506
39586
|
});
|
|
39507
|
-
const localDaemonIdForDispatch = readNonEmptyString2(loadConfig2().machineId) || void 0;
|
|
39508
39587
|
components.dispatchMeshCommand(node.daemonId, "agent_command", {
|
|
39509
39588
|
targetSessionId: sessionId,
|
|
39510
39589
|
cliType: providerType,
|
|
@@ -39514,7 +39593,8 @@ Next step: ${nextStep}`;
|
|
|
39514
39593
|
meshId,
|
|
39515
39594
|
nodeId,
|
|
39516
39595
|
taskId: task.id,
|
|
39517
|
-
...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {}
|
|
39596
|
+
...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {},
|
|
39597
|
+
...sourceCoordinatorSessionId ? { coordinatorSessionId: sourceCoordinatorSessionId } : {}
|
|
39518
39598
|
}
|
|
39519
39599
|
}).then(() => {
|
|
39520
39600
|
updateSessionDeliveryStatus(delivery2.id, "delivered");
|
|
@@ -39539,12 +39619,16 @@ Next step: ${nextStep}`;
|
|
|
39539
39619
|
const inst = components.instanceManager.getInstance(sessionId);
|
|
39540
39620
|
if (inst && typeof inst.updateSettings === "function") {
|
|
39541
39621
|
const localDaemonId = readNonEmptyString2(loadConfig2().machineId);
|
|
39622
|
+
const localSourceCoordinatorSessionId = readNonEmptyString2(task.sourceCoordinatorSessionId);
|
|
39542
39623
|
inst.updateSettings({
|
|
39543
39624
|
meshNodeFor: meshId,
|
|
39544
39625
|
meshNodeId: nodeId,
|
|
39545
39626
|
launchedByCoordinator: true,
|
|
39546
39627
|
autoApprove: resolveDelegatedWorkerAutoApprove(mesh?.policy, node?.policy),
|
|
39547
|
-
...localDaemonId ? { meshCoordinatorDaemonId: localDaemonId } : {}
|
|
39628
|
+
...localDaemonId ? { meshCoordinatorDaemonId: localDaemonId } : {},
|
|
39629
|
+
// (3) Stamp the originating coordinator session for session-anchored routing
|
|
39630
|
+
// of this co-located worker's completion. Absent → daemon-level fallback.
|
|
39631
|
+
...localSourceCoordinatorSessionId ? { meshCoordinatorSessionId: localSourceCoordinatorSessionId } : {}
|
|
39548
39632
|
});
|
|
39549
39633
|
}
|
|
39550
39634
|
} catch {
|
|
@@ -39557,7 +39641,9 @@ Next step: ${nextStep}`;
|
|
|
39557
39641
|
taskId: task.id,
|
|
39558
39642
|
kind: "task",
|
|
39559
39643
|
message: task.message,
|
|
39560
|
-
status: "delivering"
|
|
39644
|
+
status: "delivering",
|
|
39645
|
+
...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { sourceCoordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {},
|
|
39646
|
+
...readNonEmptyString2(loadConfig2().machineId) ? { sourceCoordinatorDaemonId: readNonEmptyString2(loadConfig2().machineId) } : {}
|
|
39561
39647
|
});
|
|
39562
39648
|
components.cliManager.handleCliCommand("agent_command", {
|
|
39563
39649
|
targetSessionId: sessionId,
|
|
@@ -40207,6 +40293,9 @@ Next step: ${nextStep}`;
|
|
|
40207
40293
|
const workerCoordinatorDaemonId = readNonEmptyString2(
|
|
40208
40294
|
sourceSession?.getState()?.settings?.meshCoordinatorDaemonId
|
|
40209
40295
|
);
|
|
40296
|
+
const workerCoordinatorSessionId = readNonEmptyString2(
|
|
40297
|
+
sourceSession?.getState()?.settings?.meshCoordinatorSessionId
|
|
40298
|
+
) || readNonEmptyString2(args.metadataEvent.meshCoordinatorSessionId);
|
|
40210
40299
|
if (components.onMeshCoordinatorEventForwarded) {
|
|
40211
40300
|
try {
|
|
40212
40301
|
const surfacedPreview = resolveMeshSurfacedSessionPreview(args.metadataEvent);
|
|
@@ -40587,7 +40676,12 @@ Next step: ${nextStep}`;
|
|
|
40587
40676
|
workspace: readNonEmptyString2(args.metadataEvent.workspace) || readNonEmptyString2(args.metadataEvent.workspaceName),
|
|
40588
40677
|
metadataEvent: {
|
|
40589
40678
|
...args.metadataEvent,
|
|
40590
|
-
...recoveryContext ? { recoveryContext } : {}
|
|
40679
|
+
...recoveryContext ? { recoveryContext } : {},
|
|
40680
|
+
// Stash the coordinator session id INSIDE metadataEvent too, so it survives the
|
|
40681
|
+
// P2P relay serialization (buildForwardPayloadFromPending spreads metadata; the
|
|
40682
|
+
// handleMeshForwardEvent whitelist reads it back) — a top-level field alone would
|
|
40683
|
+
// be dropped when the event crosses a machine boundary.
|
|
40684
|
+
...workerCoordinatorSessionId ? { meshCoordinatorSessionId: workerCoordinatorSessionId } : {}
|
|
40591
40685
|
},
|
|
40592
40686
|
// Silent lifecycle events (agent:ready / agent:generating_started) carry no
|
|
40593
40687
|
// coordinator message; they are queued only so the coordinator re-runs the
|
|
@@ -40595,10 +40689,13 @@ Next step: ${nextStep}`;
|
|
|
40595
40689
|
// entries without a coordinatorMessage, so a live CLI coordinator is not spammed.
|
|
40596
40690
|
...messageText ? { coordinatorMessage: messageText } : {},
|
|
40597
40691
|
queuedAt: Date.now(),
|
|
40598
|
-
...workerCoordinatorDaemonId ? { targetCoordinatorDaemonId: workerCoordinatorDaemonId } : {}
|
|
40692
|
+
...workerCoordinatorDaemonId ? { targetCoordinatorDaemonId: workerCoordinatorDaemonId } : {},
|
|
40693
|
+
// Top-level session anchor for the local PHASE 2 strict-match on the coordinator
|
|
40694
|
+
// daemon. Absent → daemon-level broadcast (legacy / single-coordinator path).
|
|
40695
|
+
...workerCoordinatorSessionId ? { targetCoordinatorSessionId: workerCoordinatorSessionId } : {}
|
|
40599
40696
|
};
|
|
40600
40697
|
if (queuePendingMeshCoordinatorEvent(pendingEvent)) {
|
|
40601
|
-
LOG2.info("MeshEvents", `Queued ${args.event} for coordinator (mesh ${args.meshId}${workerCoordinatorDaemonId ? `, coordinator daemon ${workerCoordinatorDaemonId}` : ""})`);
|
|
40698
|
+
LOG2.info("MeshEvents", `Queued ${args.event} for coordinator (mesh ${args.meshId}${workerCoordinatorDaemonId ? `, coordinator daemon ${workerCoordinatorDaemonId}` : ""}${workerCoordinatorSessionId ? `, coordinator session ${workerCoordinatorSessionId}` : ""})`);
|
|
40602
40699
|
}
|
|
40603
40700
|
return { success: true, forwarded: 0 };
|
|
40604
40701
|
}
|
|
@@ -40623,6 +40720,13 @@ Next step: ${nextStep}`;
|
|
|
40623
40720
|
targetSessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId) || readNonEmptyString2(payload.instanceId),
|
|
40624
40721
|
providerType: readNonEmptyString2(payload.providerType),
|
|
40625
40722
|
providerSessionId: readNonEmptyString2(payload.providerSessionId),
|
|
40723
|
+
// Preserve the originating coordinator SESSION id across the machine boundary so
|
|
40724
|
+
// the completion routes back to the exact coordinator session (multi-coordinator).
|
|
40725
|
+
// buildForwardPayloadFromPending spreads the worker event's metadata, so the id
|
|
40726
|
+
// arrives as payload.meshCoordinatorSessionId; the top-level targetCoordinatorSessionId
|
|
40727
|
+
// is also accepted as a fallback. injectMeshSystemMessage re-derives the routing
|
|
40728
|
+
// anchors from this. Absent → daemon-level fallback (version-skew safe).
|
|
40729
|
+
meshCoordinatorSessionId: readNonEmptyString2(payload.meshCoordinatorSessionId) || readNonEmptyString2(payload.targetCoordinatorSessionId),
|
|
40626
40730
|
// Carry the session identity fields the worker provider event emits so the
|
|
40627
40731
|
// coordinator's mirror (updateMeshOwnedSession) gets a real workspace/title/
|
|
40628
40732
|
// settings. Without these the remote-relay hop reconstructs metadataEvent with
|
|
@@ -41541,7 +41645,8 @@ Next step: ${nextStep}`;
|
|
|
41541
41645
|
if (!meshId) continue;
|
|
41542
41646
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
41543
41647
|
const modalParked = status === "waiting_choice" || status === "waiting_approval";
|
|
41544
|
-
|
|
41648
|
+
const sessionId = readNonEmptyString2(state.instanceId);
|
|
41649
|
+
out.push({ meshId, instance: inst, sessionId, idle: status === "idle", modalParked });
|
|
41545
41650
|
}
|
|
41546
41651
|
return out;
|
|
41547
41652
|
}
|
|
@@ -41553,6 +41658,44 @@ Next step: ${nextStep}`;
|
|
|
41553
41658
|
...force ? { force: true } : {}
|
|
41554
41659
|
});
|
|
41555
41660
|
}
|
|
41661
|
+
function recordHeldTerminalEventsToLedger(meshId, drainDaemonIds, reason, heldForCoordinatorCount) {
|
|
41662
|
+
let pending;
|
|
41663
|
+
try {
|
|
41664
|
+
pending = getPendingMeshCoordinatorEvents(meshId, drainDaemonIds.length > 0 ? drainDaemonIds : void 0);
|
|
41665
|
+
} catch {
|
|
41666
|
+
return;
|
|
41667
|
+
}
|
|
41668
|
+
for (const event of pending) {
|
|
41669
|
+
if (!shouldForceInjectMeshEvent(event.event)) continue;
|
|
41670
|
+
const fingerprint = buildPendingEventFingerprint(event);
|
|
41671
|
+
const key = `${meshId}::${fingerprint || `${event.event}::${event.nodeId || ""}::${event.queuedAt}`}`;
|
|
41672
|
+
if (heldEventLedgerRecorded.has(key)) continue;
|
|
41673
|
+
heldEventLedgerRecorded.add(key);
|
|
41674
|
+
const finalSummary = readMeshCompletionSummary(event.metadataEvent);
|
|
41675
|
+
try {
|
|
41676
|
+
appendLedgerEntry(meshId, {
|
|
41677
|
+
kind: "event_held",
|
|
41678
|
+
...event.nodeId ? { nodeId: event.nodeId } : {},
|
|
41679
|
+
payload: {
|
|
41680
|
+
event: event.event,
|
|
41681
|
+
reason,
|
|
41682
|
+
recoverable: true,
|
|
41683
|
+
heldForCoordinators: heldForCoordinatorCount,
|
|
41684
|
+
nodeLabel: event.nodeLabel,
|
|
41685
|
+
...event.workspace ? { workspace: event.workspace } : {},
|
|
41686
|
+
targetCoordinatorDaemonId: event.targetCoordinatorDaemonId ?? null,
|
|
41687
|
+
queuedAt: event.queuedAt,
|
|
41688
|
+
...fingerprint ? { fingerprint } : {},
|
|
41689
|
+
...finalSummary ? { finalSummary } : {}
|
|
41690
|
+
}
|
|
41691
|
+
});
|
|
41692
|
+
LOG2.info("MeshReconcile", `Ledger-recorded held ${event.event} for mesh ${meshId} (reason ${reason}) \u2014 recoverable from ledger`);
|
|
41693
|
+
} catch (e) {
|
|
41694
|
+
heldEventLedgerRecorded.delete(key);
|
|
41695
|
+
LOG2.warn("MeshReconcile", `Failed to ledger-record held ${event.event} for mesh ${meshId}: ${e?.message || e}`);
|
|
41696
|
+
}
|
|
41697
|
+
}
|
|
41698
|
+
}
|
|
41556
41699
|
async function runMeshReconcileTick(components) {
|
|
41557
41700
|
const localDaemonId = readNonEmptyString2(loadConfig2().machineId) || void 0;
|
|
41558
41701
|
const drainDaemonIds = resolveCoordinatorDaemonIds(components);
|
|
@@ -41637,6 +41780,21 @@ Next step: ${nextStep}`;
|
|
|
41637
41780
|
if (targetCoordinators.length === 0) {
|
|
41638
41781
|
if (modalParkedCoordinators.length > 0) {
|
|
41639
41782
|
LOG2.info("MeshReconcile", `Reconcile skip \u2192 modal-parked: holding pending event(s) for mesh ${meshId} (${modalParkedCoordinators.length} coordinator(s) awaiting a modal answer; events left queued)`);
|
|
41783
|
+
let hasPending = true;
|
|
41784
|
+
if (store) {
|
|
41785
|
+
try {
|
|
41786
|
+
hasPending = store.pendingEventCount(meshId) > 0;
|
|
41787
|
+
} catch {
|
|
41788
|
+
}
|
|
41789
|
+
}
|
|
41790
|
+
if (hasPending) {
|
|
41791
|
+
recordHeldTerminalEventsToLedger(
|
|
41792
|
+
meshId,
|
|
41793
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId ? [localDaemonId] : [],
|
|
41794
|
+
"modal_parked",
|
|
41795
|
+
modalParkedCoordinators.length
|
|
41796
|
+
);
|
|
41797
|
+
}
|
|
41640
41798
|
}
|
|
41641
41799
|
continue;
|
|
41642
41800
|
}
|
|
@@ -41661,12 +41819,55 @@ Next step: ${nextStep}`;
|
|
|
41661
41819
|
const mode = forceOnly ? "force-drain \u2192 generating" : "inject \u2192 idle";
|
|
41662
41820
|
LOG2.info("MeshReconcile", `Reconcile ${mode}: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
|
|
41663
41821
|
for (const pending of pendingEvents) {
|
|
41822
|
+
const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
|
|
41823
|
+
if (wantSession) {
|
|
41824
|
+
const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
|
|
41825
|
+
if (matched.length === 0) {
|
|
41826
|
+
holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
|
|
41827
|
+
continue;
|
|
41828
|
+
}
|
|
41829
|
+
for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
|
|
41830
|
+
continue;
|
|
41831
|
+
}
|
|
41664
41832
|
for (const c of targetCoordinators) {
|
|
41665
41833
|
injectPendingIntoCoordinator(c.instance, pending);
|
|
41666
41834
|
}
|
|
41667
41835
|
}
|
|
41668
41836
|
}
|
|
41669
41837
|
}
|
|
41838
|
+
function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
41839
|
+
const queuedAt = typeof pending.queuedAt === "number" ? pending.queuedAt : Date.now();
|
|
41840
|
+
if (Date.now() - queuedAt <= STRICT_SESSION_MATCH_TTL_MS) {
|
|
41841
|
+
try {
|
|
41842
|
+
queuePendingMeshCoordinatorEvent(pending);
|
|
41843
|
+
LOG2.info("MeshReconcile", `Strict route hold: coordinator session ${wantSession} not live on mesh ${meshId} \u2014 re-queued (${pending.event})`);
|
|
41844
|
+
} catch (e) {
|
|
41845
|
+
LOG2.warn("MeshReconcile", `Strict route re-queue failed for ${pending.event} on mesh ${meshId}: ${e?.message || e}`);
|
|
41846
|
+
}
|
|
41847
|
+
return;
|
|
41848
|
+
}
|
|
41849
|
+
const finalSummary = readMeshCompletionSummary(pending.metadataEvent || {});
|
|
41850
|
+
try {
|
|
41851
|
+
appendLedgerEntry(meshId, {
|
|
41852
|
+
kind: "event_held",
|
|
41853
|
+
...pending.nodeId ? { nodeId: pending.nodeId } : {},
|
|
41854
|
+
payload: {
|
|
41855
|
+
event: pending.event,
|
|
41856
|
+
reason: "strict_route_expired",
|
|
41857
|
+
recoverable: true,
|
|
41858
|
+
targetCoordinatorSessionId: wantSession,
|
|
41859
|
+
targetCoordinatorDaemonId: pending.targetCoordinatorDaemonId ?? null,
|
|
41860
|
+
nodeLabel: pending.nodeLabel,
|
|
41861
|
+
...pending.workspace ? { workspace: pending.workspace } : {},
|
|
41862
|
+
queuedAt,
|
|
41863
|
+
...finalSummary ? { finalSummary } : {}
|
|
41864
|
+
}
|
|
41865
|
+
});
|
|
41866
|
+
LOG2.warn("MeshReconcile", `Strict route expire: coordinator session ${wantSession} never returned for mesh ${meshId} \u2014 recorded to ledger (recoverable), dropped (${pending.event})`);
|
|
41867
|
+
} catch (e) {
|
|
41868
|
+
LOG2.warn("MeshReconcile", `Failed to ledger-expire strict-unmatched ${pending.event} for mesh ${meshId}: ${e?.message || e}`);
|
|
41869
|
+
}
|
|
41870
|
+
}
|
|
41670
41871
|
async function retryUnresolvedDelegateForwards(components) {
|
|
41671
41872
|
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
41672
41873
|
if (!dispatchMeshCommand) return;
|
|
@@ -41884,6 +42085,11 @@ Next step: ${nextStep}`;
|
|
|
41884
42085
|
meshId: readNonEmptyString2(event?.meshId),
|
|
41885
42086
|
nodeId: readNonEmptyString2(event?.nodeId) || readNonEmptyString2(metadata.meshNodeId),
|
|
41886
42087
|
workspace: readNonEmptyString2(event?.workspace) || readNonEmptyString2(metadata.workspace),
|
|
42088
|
+
// Preserve the originating coordinator session id across the relay. It is normally
|
|
42089
|
+
// carried inside metadataEvent.meshCoordinatorSessionId (spread below), but pass the
|
|
42090
|
+
// top-level field through explicitly too so the handleMeshForwardEvent whitelist
|
|
42091
|
+
// recovers it regardless of which carrier the producing daemon used.
|
|
42092
|
+
...readNonEmptyString2(event?.targetCoordinatorSessionId) ? { targetCoordinatorSessionId: readNonEmptyString2(event.targetCoordinatorSessionId) } : {},
|
|
41887
42093
|
...metadata
|
|
41888
42094
|
};
|
|
41889
42095
|
}
|
|
@@ -41908,6 +42114,8 @@ Next step: ${nextStep}`;
|
|
|
41908
42114
|
}
|
|
41909
42115
|
var DEFAULT_RECONCILE_INTERVAL_MS;
|
|
41910
42116
|
var DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
42117
|
+
var heldEventLedgerRecorded;
|
|
42118
|
+
var STRICT_SESSION_MATCH_TTL_MS;
|
|
41911
42119
|
var init_mesh_reconcile_loop = __esm2({
|
|
41912
42120
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
41913
42121
|
"use strict";
|
|
@@ -41915,6 +42123,7 @@ Next step: ${nextStep}`;
|
|
|
41915
42123
|
init_mesh_config();
|
|
41916
42124
|
init_logger();
|
|
41917
42125
|
init_mesh_events_pending();
|
|
42126
|
+
init_mesh_ledger();
|
|
41918
42127
|
init_mesh_runtime_store();
|
|
41919
42128
|
init_mesh_events_coordinator();
|
|
41920
42129
|
init_mesh_unresolved_forward_outbox();
|
|
@@ -41926,6 +42135,8 @@ Next step: ${nextStep}`;
|
|
|
41926
42135
|
init_chat_message_normalization();
|
|
41927
42136
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
41928
42137
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
42138
|
+
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
42139
|
+
STRICT_SESSION_MATCH_TTL_MS = 6e4;
|
|
41929
42140
|
}
|
|
41930
42141
|
});
|
|
41931
42142
|
var mesh_events_exports = {};
|
|
@@ -64681,7 +64892,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
64681
64892
|
meshNodeFor: assignment.meshId,
|
|
64682
64893
|
...assignment.nodeId ? { meshNodeId: assignment.nodeId } : {},
|
|
64683
64894
|
...assignment.taskId ? { meshActiveTaskId: assignment.taskId } : {},
|
|
64684
|
-
...assignment.coordinatorDaemonId ? { meshCoordinatorDaemonId: assignment.coordinatorDaemonId } : {}
|
|
64895
|
+
...assignment.coordinatorDaemonId ? { meshCoordinatorDaemonId: assignment.coordinatorDaemonId } : {},
|
|
64896
|
+
// Session-level routing anchor: the originating coordinator session, so this
|
|
64897
|
+
// worker's completion events route back to the exact session that dispatched it.
|
|
64898
|
+
...assignment.coordinatorSessionId ? { meshCoordinatorSessionId: assignment.coordinatorSessionId } : {}
|
|
64685
64899
|
};
|
|
64686
64900
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
64687
64901
|
}
|
|
@@ -67657,6 +67871,12 @@ Enable and detect this provider from the Machine Providers page before starting
|
|
|
67657
67871
|
);
|
|
67658
67872
|
}
|
|
67659
67873
|
const key = crypto5.randomUUID();
|
|
67874
|
+
{
|
|
67875
|
+
const coordinatorMeshId = options?.settingsOverride?.meshCoordinatorFor;
|
|
67876
|
+
if (typeof coordinatorMeshId === "string" && coordinatorMeshId.trim()) {
|
|
67877
|
+
options = { ...options, extraEnv: { ...options?.extraEnv || {}, ADHDEV_COORDINATOR_SESSION_ID: key } };
|
|
67878
|
+
}
|
|
67879
|
+
}
|
|
67660
67880
|
const sessionRegistry = this.deps.getSessionRegistry?.() || null;
|
|
67661
67881
|
if (provider && provider.category === "acp") {
|
|
67662
67882
|
const instanceManager2 = this.deps.getInstanceManager();
|
|
@@ -74017,6 +74237,40 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
74017
74237
|
const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
|
|
74018
74238
|
return sessionId ? [sessionId] : [];
|
|
74019
74239
|
}
|
|
74240
|
+
function collectMeshNodeHostedSessionIds(node) {
|
|
74241
|
+
const ids = /* @__PURE__ */ new Set();
|
|
74242
|
+
for (const id of readCachedInlineMeshActiveSessions(node)) ids.add(id);
|
|
74243
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
74244
|
+
for (const value of [
|
|
74245
|
+
node?.activeSessions,
|
|
74246
|
+
node?.active_sessions,
|
|
74247
|
+
node?.activeSessionDetails,
|
|
74248
|
+
node?.active_session_details,
|
|
74249
|
+
node?.sessions,
|
|
74250
|
+
node?.sessionDetails,
|
|
74251
|
+
node?.session_details,
|
|
74252
|
+
readObjectRecord(node?.lastProbe).sessions,
|
|
74253
|
+
readObjectRecord(node?.last_probe).sessions,
|
|
74254
|
+
cachedStatus.activeSessions,
|
|
74255
|
+
cachedStatus.active_sessions,
|
|
74256
|
+
cachedStatus.activeSessionDetails,
|
|
74257
|
+
cachedStatus.active_session_details,
|
|
74258
|
+
cachedStatus.sessions
|
|
74259
|
+
]) {
|
|
74260
|
+
if (!Array.isArray(value)) continue;
|
|
74261
|
+
for (const item of value) {
|
|
74262
|
+
if (typeof item === "string") {
|
|
74263
|
+
const id2 = readStringValue(item);
|
|
74264
|
+
if (id2) ids.add(id2);
|
|
74265
|
+
continue;
|
|
74266
|
+
}
|
|
74267
|
+
const record2 = readObjectRecord(item);
|
|
74268
|
+
const id = readStringValue(record2.id, record2.sessionId, record2.session_id, record2.runtimeSessionId, record2.instanceId);
|
|
74269
|
+
if (id) ids.add(id);
|
|
74270
|
+
}
|
|
74271
|
+
}
|
|
74272
|
+
return ids;
|
|
74273
|
+
}
|
|
74020
74274
|
function resolveMeshNodeAttribution(node) {
|
|
74021
74275
|
const record2 = readObjectRecord(node);
|
|
74022
74276
|
return {
|
|
@@ -75895,25 +76149,47 @@ ${mergeTreeErr?.stderr || ""}`;
|
|
|
75895
76149
|
* controlbar commands do not — so the controlbar buttons appear to do nothing.
|
|
75896
76150
|
*
|
|
75897
76151
|
* Mirror the existing node-level remote-forward pattern (fast_forward_mesh_node etc.):
|
|
75898
|
-
* scan the
|
|
75899
|
-
*
|
|
75900
|
-
*
|
|
75901
|
-
*
|
|
76152
|
+
* scan the candidate mesh nodes for the one hosting the targetSessionId, and return its
|
|
76153
|
+
* daemonId when that daemonId is a remote daemon (i.e. not this coordinator's own
|
|
76154
|
+
* statusInstanceId). Returns undefined for a locally-hosted session (no forward — execute
|
|
76155
|
+
* locally as before) or when ownership can't be resolved.
|
|
76156
|
+
*
|
|
76157
|
+
* The candidate set spans BOTH the cached inline-mesh nodes and the live aggregate
|
|
76158
|
+
* mesh-status snapshots. The inline cache reliably carries only each node's single primary
|
|
76159
|
+
* session (cachedStatus.activeSession), so a worker hosting more than one session exposes its
|
|
76160
|
+
* non-primary sessions only on the aggregate snapshot nodes (status.activeSessions /
|
|
76161
|
+
* activeSessionDetails, built from live session records). collectMeshNodeHostedSessionIds does
|
|
76162
|
+
* the wider plural-shape scan so a controlbar/modal command targeting a non-primary remote
|
|
76163
|
+
* session still resolves its owner — the singular readCachedInlineMeshActiveSessions semantics
|
|
76164
|
+
* other consumers depend on stay untouched.
|
|
75902
76165
|
*/
|
|
75903
76166
|
resolveRemoteMeshSessionOwnerDaemonId(sessionId) {
|
|
75904
76167
|
const trimmed = typeof sessionId === "string" ? sessionId.trim() : "";
|
|
75905
76168
|
if (!trimmed) return void 0;
|
|
75906
76169
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
75907
|
-
for (const node of this.
|
|
75908
|
-
|
|
75909
|
-
if (!nodeSessions.includes(trimmed)) continue;
|
|
76170
|
+
for (const node of this.collectMeshSessionOwnerCandidateNodes()) {
|
|
76171
|
+
if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
|
|
75910
76172
|
const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
|
|
75911
|
-
if (!nodeDaemonId)
|
|
76173
|
+
if (!nodeDaemonId) continue;
|
|
75912
76174
|
if (selfDaemonId && nodeDaemonId === selfDaemonId) return void 0;
|
|
75913
76175
|
return nodeDaemonId;
|
|
75914
76176
|
}
|
|
75915
76177
|
return void 0;
|
|
75916
76178
|
}
|
|
76179
|
+
/**
|
|
76180
|
+
* Candidate nodes for remote-session owner resolution: the cached inline-mesh nodes (which
|
|
76181
|
+
* carry each node's primary session) plus the nodes from every cached aggregate mesh-status
|
|
76182
|
+
* snapshot (which carry each node's full live session list). getCachedInlineMeshNodes()
|
|
76183
|
+
* returns a fresh array, so appending the aggregate nodes never mutates cached state.
|
|
76184
|
+
*/
|
|
76185
|
+
collectMeshSessionOwnerCandidateNodes() {
|
|
76186
|
+
const nodes = this.getCachedInlineMeshNodes();
|
|
76187
|
+
for (const cached3 of this.aggregateMeshStatusCache.values()) {
|
|
76188
|
+
const snapshotNodes = cached3?.snapshot?.nodes;
|
|
76189
|
+
if (Array.isArray(snapshotNodes)) nodes.push(...snapshotNodes);
|
|
76190
|
+
}
|
|
76191
|
+
return nodes;
|
|
76192
|
+
}
|
|
75917
76193
|
getCachedInlineMesh(meshId, inlineMesh) {
|
|
75918
76194
|
if (inlineMesh && typeof inlineMesh === "object") {
|
|
75919
76195
|
return this.warmInlineMeshCache(meshId, inlineMesh);
|
|
@@ -77933,7 +78209,10 @@ ${hintLines.join("\n")}` : "",
|
|
|
77933
78209
|
{
|
|
77934
78210
|
meshId: dispatchMeshContext.meshId,
|
|
77935
78211
|
nodeId: dispatchMeshContext.nodeId,
|
|
77936
|
-
coordinatorDaemonId: dispatchMeshContext.coordinatorDaemonId
|
|
78212
|
+
coordinatorDaemonId: dispatchMeshContext.coordinatorDaemonId,
|
|
78213
|
+
// Session-level anchor: preserved across the P2P dispatch to a
|
|
78214
|
+
// remote worker so its completion echoes back to the right session.
|
|
78215
|
+
coordinatorSessionId: dispatchMeshContext.coordinatorSessionId
|
|
77937
78216
|
}
|
|
77938
78217
|
);
|
|
77939
78218
|
if (stamp) inst.updateSettings(stamp);
|