@adhdev/daemon-core 0.9.82-rc.327 → 0.9.82-rc.329
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/cli-adapters/provider-cli-shared.d.ts +1 -1
- package/dist/git/change-impact-config.d.ts +159 -0
- package/dist/git/git-status.d.ts +14 -0
- package/dist/git/index.d.ts +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1140 -607
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1090 -564
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-active-work.d.ts +66 -0
- package/dist/mesh/mesh-events-stale.d.ts +1 -1
- package/dist/providers/status-monitor.d.ts +7 -7
- package/dist/shared-types.d.ts +1 -1
- package/package.json +2 -2
- package/src/agent-stream/provider-adapter.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +2 -2
- package/src/cli-adapters/provider-cli-shared.ts +1 -1
- package/src/commands/chat-commands.ts +1 -1
- package/src/commands/cli-manager.ts +1 -1
- package/src/commands/router.ts +46 -0
- package/src/git/change-impact-config.ts +354 -0
- package/src/git/git-status.ts +182 -16
- package/src/git/index.ts +16 -0
- package/src/index.ts +2 -2
- package/src/mesh/mesh-active-work.ts +154 -0
- package/src/mesh/mesh-events-coordinator.ts +13 -12
- package/src/mesh/mesh-events-stale.ts +4 -4
- package/src/mesh/mesh-events-utils.ts +3 -3
- package/src/mesh/mesh-reconcile-loop.ts +144 -1
- package/src/providers/acp-provider-instance.ts +6 -5
- package/src/providers/cli-provider-instance.ts +14 -10
- package/src/providers/extension-provider-instance.ts +7 -6
- package/src/providers/ide-provider-instance.ts +10 -6
- package/src/providers/read-chat-contract.ts +1 -1
- package/src/providers/status-monitor.d.ts +7 -7
- package/src/providers/status-monitor.ts +37 -22
- package/src/shared-types.ts +3 -0
- package/src/status/reporter.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -313,10 +313,10 @@ function readInjected(value) {
|
|
|
313
313
|
}
|
|
314
314
|
function getDaemonBuildInfo() {
|
|
315
315
|
if (cached) return cached;
|
|
316
|
-
const commit = readInjected(true ? "
|
|
317
|
-
const commitShort = readInjected(true ? "
|
|
318
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
319
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
316
|
+
const commit = readInjected(true ? "9277ba79593a0feae0e17de0204856825a199ebe" : void 0) ?? "unknown";
|
|
317
|
+
const commitShort = readInjected(true ? "9277ba79" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
318
|
+
const version = readInjected(true ? "0.9.82-rc.329" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
319
|
+
const builtAt = readInjected(true ? "2026-06-19T15:56:44.269Z" : void 0);
|
|
320
320
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
321
321
|
return cached;
|
|
322
322
|
}
|
|
@@ -327,6 +327,247 @@ var init_build_info = __esm({
|
|
|
327
327
|
}
|
|
328
328
|
});
|
|
329
329
|
|
|
330
|
+
// src/git/change-impact-config.ts
|
|
331
|
+
function isRecord(value) {
|
|
332
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
333
|
+
}
|
|
334
|
+
function isStringArray(value) {
|
|
335
|
+
return Array.isArray(value) && value.every((v) => typeof v === "string" && v.length > 0);
|
|
336
|
+
}
|
|
337
|
+
function validateTarget(value, key, errors) {
|
|
338
|
+
if (!isRecord(value)) {
|
|
339
|
+
errors.push(`impactTargets.${key} must be an object`);
|
|
340
|
+
return void 0;
|
|
341
|
+
}
|
|
342
|
+
const { recommendedCommand } = value;
|
|
343
|
+
if (typeof recommendedCommand !== "string" || !recommendedCommand.length) {
|
|
344
|
+
errors.push(`impactTargets.${key}.recommendedCommand must be a non-empty string`);
|
|
345
|
+
return void 0;
|
|
346
|
+
}
|
|
347
|
+
for (const k of Object.keys(value)) {
|
|
348
|
+
if (k !== "recommendedCommand") errors.push(`impactTargets.${key}.${k} is not a recognized field (only recommendedCommand)`);
|
|
349
|
+
}
|
|
350
|
+
return { recommendedCommand };
|
|
351
|
+
}
|
|
352
|
+
function validateChangeImpactConfig(raw, source = "inline") {
|
|
353
|
+
const errors = [];
|
|
354
|
+
if (!isRecord(raw)) {
|
|
355
|
+
return { valid: false, errors: [`${source}: config must be an object`] };
|
|
356
|
+
}
|
|
357
|
+
const config = {};
|
|
358
|
+
if (raw.daemonRuntimePackages !== void 0) {
|
|
359
|
+
if (isStringArray(raw.daemonRuntimePackages)) config.daemonRuntimePackages = [...raw.daemonRuntimePackages];
|
|
360
|
+
else errors.push("daemonRuntimePackages must be an array of non-empty strings");
|
|
361
|
+
}
|
|
362
|
+
if (raw.webOnlyPackages !== void 0) {
|
|
363
|
+
if (isStringArray(raw.webOnlyPackages)) config.webOnlyPackages = [...raw.webOnlyPackages];
|
|
364
|
+
else errors.push("webOnlyPackages must be an array of non-empty strings");
|
|
365
|
+
}
|
|
366
|
+
if (raw.nonRuntimeRootFilePatterns !== void 0) {
|
|
367
|
+
if (isStringArray(raw.nonRuntimeRootFilePatterns)) config.nonRuntimeRootFilePatterns = [...raw.nonRuntimeRootFilePatterns];
|
|
368
|
+
else errors.push("nonRuntimeRootFilePatterns must be an array of non-empty strings");
|
|
369
|
+
}
|
|
370
|
+
if (raw.impactTargets !== void 0) {
|
|
371
|
+
if (!isRecord(raw.impactTargets)) {
|
|
372
|
+
errors.push("impactTargets must be an object");
|
|
373
|
+
} else {
|
|
374
|
+
const targets = {};
|
|
375
|
+
for (const key of Object.keys(raw.impactTargets)) {
|
|
376
|
+
if (key !== "daemon" && key !== "web" && key !== "none") {
|
|
377
|
+
errors.push(`impactTargets.${key} is not a recognized impact kind (daemon|web|none)`);
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
const target = validateTarget(raw.impactTargets[key], key, errors);
|
|
381
|
+
if (target) targets[key] = target;
|
|
382
|
+
}
|
|
383
|
+
if (Object.keys(targets).length) config.impactTargets = targets;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
for (const key of Object.keys(raw)) {
|
|
387
|
+
if (!["daemonRuntimePackages", "webOnlyPackages", "nonRuntimeRootFilePatterns", "impactTargets"].includes(key)) {
|
|
388
|
+
errors.push(`unknown config key '${key}'`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return { valid: errors.length === 0, errors, config: errors.length === 0 ? config : void 0 };
|
|
392
|
+
}
|
|
393
|
+
function parseConfigText(path42, text) {
|
|
394
|
+
if (/\.json$/i.test(path42)) return JSON.parse(text);
|
|
395
|
+
return yaml.load(text);
|
|
396
|
+
}
|
|
397
|
+
function loadChangeImpactConfig(repoRoot) {
|
|
398
|
+
for (const relative5 of CHANGE_IMPACT_CONFIG_LOCATIONS) {
|
|
399
|
+
const configPath = (0, import_path.join)(repoRoot, relative5);
|
|
400
|
+
if (!(0, import_fs.existsSync)(configPath)) continue;
|
|
401
|
+
try {
|
|
402
|
+
const text = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
403
|
+
let mtimeMs = 0;
|
|
404
|
+
try {
|
|
405
|
+
mtimeMs = (0, import_fs.statSync)(configPath).mtimeMs;
|
|
406
|
+
} catch {
|
|
407
|
+
mtimeMs = text.length;
|
|
408
|
+
}
|
|
409
|
+
const parsed = parseConfigText(configPath, text);
|
|
410
|
+
const validation = validateChangeImpactConfig(parsed, relative5);
|
|
411
|
+
if (!validation.valid) {
|
|
412
|
+
return {
|
|
413
|
+
source: relative5,
|
|
414
|
+
sourceType: "invalid",
|
|
415
|
+
path: configPath,
|
|
416
|
+
error: validation.errors.join("; "),
|
|
417
|
+
sourceKey: `invalid:${configPath}:${mtimeMs}`
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
return {
|
|
421
|
+
config: validation.config,
|
|
422
|
+
source: relative5,
|
|
423
|
+
sourceType: "repo_file",
|
|
424
|
+
path: configPath,
|
|
425
|
+
sourceKey: `file:${configPath}:${mtimeMs}`
|
|
426
|
+
};
|
|
427
|
+
} catch (error) {
|
|
428
|
+
return {
|
|
429
|
+
source: relative5,
|
|
430
|
+
sourceType: "invalid",
|
|
431
|
+
path: configPath,
|
|
432
|
+
error: error?.message || String(error),
|
|
433
|
+
sourceKey: `error:${configPath}`
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
source: "unavailable",
|
|
439
|
+
sourceType: "unavailable",
|
|
440
|
+
error: `No change-impact config found. Checked: ${CHANGE_IMPACT_CONFIG_LOCATIONS.join(", ")}`,
|
|
441
|
+
sourceKey: "unavailable"
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
function globToRegExp(pattern) {
|
|
445
|
+
let out = "";
|
|
446
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
447
|
+
const ch = pattern[i];
|
|
448
|
+
if (ch === "*") {
|
|
449
|
+
if (pattern[i + 1] === "*") {
|
|
450
|
+
out += ".*";
|
|
451
|
+
i++;
|
|
452
|
+
if (pattern[i + 1] === "/") i++;
|
|
453
|
+
} else {
|
|
454
|
+
out += "[^/]*";
|
|
455
|
+
}
|
|
456
|
+
} else if (ch === "?") {
|
|
457
|
+
out += "[^/]";
|
|
458
|
+
} else if (".+^${}()|[]\\".includes(ch)) {
|
|
459
|
+
out += "\\" + ch;
|
|
460
|
+
} else {
|
|
461
|
+
out += ch;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return new RegExp(`^${out}$`);
|
|
465
|
+
}
|
|
466
|
+
function listPackageDirs(packagesRoot) {
|
|
467
|
+
try {
|
|
468
|
+
return (0, import_fs.readdirSync)(packagesRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
|
|
469
|
+
} catch {
|
|
470
|
+
return [];
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
function suggestChangeImpactConfig(repoRoot) {
|
|
474
|
+
const notes = [];
|
|
475
|
+
const daemon = /* @__PURE__ */ new Set();
|
|
476
|
+
const web = /* @__PURE__ */ new Set();
|
|
477
|
+
const unclassified = [];
|
|
478
|
+
const roots = ["packages", (0, import_path.join)("oss", "packages")];
|
|
479
|
+
for (const rel of roots) {
|
|
480
|
+
const packagesRoot = (0, import_path.join)(repoRoot, rel);
|
|
481
|
+
if (!(0, import_fs.existsSync)(packagesRoot)) continue;
|
|
482
|
+
for (const name of listPackageDirs(packagesRoot)) {
|
|
483
|
+
if (/(^web[-.]|[-.]web$)/i.test(name) || /dashboard|frontend|ui$/i.test(name)) {
|
|
484
|
+
web.add(name);
|
|
485
|
+
} else {
|
|
486
|
+
daemon.add(name);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
const daemonRuntimePackages = [...daemon].sort();
|
|
491
|
+
const webOnlyPackages = [...web].sort();
|
|
492
|
+
if (!daemonRuntimePackages.length && !webOnlyPackages.length) {
|
|
493
|
+
notes.push("No packages/ or oss/packages/ directories found \u2014 defaulting to an empty draft you should fill in by hand.");
|
|
494
|
+
} else {
|
|
495
|
+
if (daemonRuntimePackages.length) notes.push(`Classified ${daemonRuntimePackages.length} package(s) as daemon-runtime (change \u2192 rebuild/redeploy + restart).`);
|
|
496
|
+
if (webOnlyPackages.length) notes.push(`Classified ${webOnlyPackages.length} web-* package(s) as web-only (change \u2192 web redeploy, no daemon restart).`);
|
|
497
|
+
notes.push("Heuristic only: confirm each package actually matches its bucket before saving.");
|
|
498
|
+
}
|
|
499
|
+
const nonRuntimeRootFilePatterns = [
|
|
500
|
+
"*.md",
|
|
501
|
+
"docs/**",
|
|
502
|
+
"LICENSE",
|
|
503
|
+
"LICENSE.*",
|
|
504
|
+
".gitignore"
|
|
505
|
+
];
|
|
506
|
+
notes.push("nonRuntimeRootFilePatterns lists root files that demonstrably cannot change daemon runtime behavior; extend with your repo markers.");
|
|
507
|
+
const suggestedConfig = {
|
|
508
|
+
...daemonRuntimePackages.length ? { daemonRuntimePackages } : {},
|
|
509
|
+
...webOnlyPackages.length ? { webOnlyPackages } : {},
|
|
510
|
+
nonRuntimeRootFilePatterns,
|
|
511
|
+
impactTargets: {
|
|
512
|
+
daemon: { recommendedCommand: "rebuild + redeploy the daemon, then restart it" },
|
|
513
|
+
web: { recommendedCommand: "redeploy the web app (no daemon restart required)" },
|
|
514
|
+
none: { recommendedCommand: "no action required" }
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
return {
|
|
518
|
+
suggestedConfig,
|
|
519
|
+
notes,
|
|
520
|
+
discoveredPackages: { daemon: daemonRuntimePackages, web: webOnlyPackages, unclassified }
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
var import_fs, import_path, yaml, CHANGE_IMPACT_CONFIG_LOCATIONS, CHANGE_IMPACT_CONFIG_SCHEMA;
|
|
524
|
+
var init_change_impact_config = __esm({
|
|
525
|
+
"src/git/change-impact-config.ts"() {
|
|
526
|
+
"use strict";
|
|
527
|
+
import_fs = require("fs");
|
|
528
|
+
import_path = require("path");
|
|
529
|
+
yaml = __toESM(require("js-yaml"));
|
|
530
|
+
CHANGE_IMPACT_CONFIG_LOCATIONS = [
|
|
531
|
+
".adhdev/change-impact.json",
|
|
532
|
+
".adhdev/change-impact.yaml",
|
|
533
|
+
".adhdev/change-impact.yml",
|
|
534
|
+
".adhdev/repo-mesh-change-impact.json",
|
|
535
|
+
".adhdev/repo-mesh-change-impact.yaml",
|
|
536
|
+
".adhdev/repo-mesh-change-impact.yml"
|
|
537
|
+
];
|
|
538
|
+
CHANGE_IMPACT_CONFIG_SCHEMA = {
|
|
539
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
540
|
+
title: "ADHDev Change Impact Config",
|
|
541
|
+
type: "object",
|
|
542
|
+
additionalProperties: false,
|
|
543
|
+
properties: {
|
|
544
|
+
daemonRuntimePackages: { type: "array", items: { type: "string", minLength: 1 } },
|
|
545
|
+
webOnlyPackages: { type: "array", items: { type: "string", minLength: 1 } },
|
|
546
|
+
nonRuntimeRootFilePatterns: { type: "array", items: { type: "string", minLength: 1 } },
|
|
547
|
+
impactTargets: {
|
|
548
|
+
type: "object",
|
|
549
|
+
additionalProperties: false,
|
|
550
|
+
properties: {
|
|
551
|
+
daemon: { $ref: "#/$defs/target" },
|
|
552
|
+
web: { $ref: "#/$defs/target" },
|
|
553
|
+
none: { $ref: "#/$defs/target" }
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
$defs: {
|
|
558
|
+
target: {
|
|
559
|
+
type: "object",
|
|
560
|
+
additionalProperties: false,
|
|
561
|
+
required: ["recommendedCommand"],
|
|
562
|
+
properties: {
|
|
563
|
+
recommendedCommand: { type: "string", minLength: 1 }
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
|
|
330
571
|
// src/git/git-status.ts
|
|
331
572
|
function isTransientGitFailure(error) {
|
|
332
573
|
return error.reason === "timeout" || error.reason === "git_command_failed";
|
|
@@ -402,16 +643,34 @@ async function collectGitRepoStatus(repo, includeSubmodules, lastCheckedAt, opti
|
|
|
402
643
|
...daemonBuildBehind ? { daemonBuildBehind } : {}
|
|
403
644
|
};
|
|
404
645
|
}
|
|
405
|
-
function
|
|
646
|
+
function resolveChangeImpactPolicy(config) {
|
|
647
|
+
const daemonRuntimePackages = new Set(
|
|
648
|
+
config?.daemonRuntimePackages && config.daemonRuntimePackages.length ? config.daemonRuntimePackages : DEFAULT_DAEMON_RUNTIME_PACKAGES
|
|
649
|
+
);
|
|
650
|
+
const webOnlyPackages = new Set(
|
|
651
|
+
config?.webOnlyPackages && config.webOnlyPackages.length ? config.webOnlyPackages : DEFAULT_WEB_ONLY_PACKAGES
|
|
652
|
+
);
|
|
653
|
+
const nonRuntimeRootFilePatterns = (config?.nonRuntimeRootFilePatterns || []).map(globToRegExp);
|
|
654
|
+
const impactTargets = {
|
|
655
|
+
daemon: config?.impactTargets?.daemon ?? DEFAULT_IMPACT_TARGETS.daemon,
|
|
656
|
+
web: config?.impactTargets?.web ?? DEFAULT_IMPACT_TARGETS.web,
|
|
657
|
+
none: config?.impactTargets?.none ?? DEFAULT_IMPACT_TARGETS.none
|
|
658
|
+
};
|
|
659
|
+
return { daemonRuntimePackages, webOnlyPackages, nonRuntimeRootFilePatterns, impactTargets };
|
|
660
|
+
}
|
|
661
|
+
function isNonRuntimeRootFile(file, policy) {
|
|
406
662
|
const base = file.slice(file.lastIndexOf("/") + 1);
|
|
407
663
|
if (/^\.(?:verify|marker|converge|ff-verify|patch-equiv|live-verify)\b/i.test(base)) return true;
|
|
408
664
|
if (/(?:^|\/)docs\//i.test(file)) return true;
|
|
409
665
|
if (/^(?:README|CHANGELOG|LICENSE|NOTICE|AUTHORS|CONTRIBUTING|CODEOWNERS)(?:\.[A-Za-z0-9]+)?$/i.test(base)) {
|
|
410
666
|
return true;
|
|
411
667
|
}
|
|
668
|
+
for (const re of policy.nonRuntimeRootFilePatterns) {
|
|
669
|
+
if (re.test(file)) return true;
|
|
670
|
+
}
|
|
412
671
|
return false;
|
|
413
672
|
}
|
|
414
|
-
async function classifyDaemonBuildChange(repoPath, buildCommit, options) {
|
|
673
|
+
async function classifyDaemonBuildChange(repoPath, buildCommit, options, policy) {
|
|
415
674
|
try {
|
|
416
675
|
const diff = await runGit(repoPath, ["diff", "--name-only", `${buildCommit}..HEAD`], options);
|
|
417
676
|
const files = diff.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
@@ -423,21 +682,47 @@ async function classifyDaemonBuildChange(repoPath, buildCommit, options) {
|
|
|
423
682
|
for (const file of files) {
|
|
424
683
|
const match = file.match(/(?:^|\/)packages\/([^/]+)\//);
|
|
425
684
|
if (!match) {
|
|
426
|
-
if (!isNonRuntimeRootFile(file)) sawRuntimeAmbiguousNonPackage = true;
|
|
685
|
+
if (!isNonRuntimeRootFile(file, policy)) sawRuntimeAmbiguousNonPackage = true;
|
|
427
686
|
continue;
|
|
428
687
|
}
|
|
429
688
|
pkgs.add(match[1]);
|
|
430
689
|
}
|
|
431
690
|
const affectedPackages = [...pkgs].sort();
|
|
432
|
-
const allBenign = !sawRuntimeAmbiguousNonPackage && affectedPackages.every((p) =>
|
|
691
|
+
const allBenign = !sawRuntimeAmbiguousNonPackage && affectedPackages.every((p) => policy.webOnlyPackages.has(p) && !policy.daemonRuntimePackages.has(p));
|
|
433
692
|
return { isDaemonAffecting: !allBenign, affectedPackages };
|
|
434
693
|
} catch {
|
|
435
694
|
return { isDaemonAffecting: true, affectedPackages: [] };
|
|
436
695
|
}
|
|
437
696
|
}
|
|
697
|
+
function resolveChangeImpactConfigForRepo(repoRoot, options) {
|
|
698
|
+
if (options.changeImpactConfig === null) {
|
|
699
|
+
return { config: null, sourceKey: "forced-default" };
|
|
700
|
+
}
|
|
701
|
+
if (options.changeImpactConfig !== void 0) {
|
|
702
|
+
let key = "injected";
|
|
703
|
+
try {
|
|
704
|
+
key = `injected:${JSON.stringify(options.changeImpactConfig)}`;
|
|
705
|
+
} catch {
|
|
706
|
+
}
|
|
707
|
+
return { config: options.changeImpactConfig, sourceKey: key };
|
|
708
|
+
}
|
|
709
|
+
if (!repoRoot) {
|
|
710
|
+
return { config: null, sourceKey: "no-repo-root" };
|
|
711
|
+
}
|
|
712
|
+
const loaded = loadChangeImpactConfig(repoRoot);
|
|
713
|
+
const cached2 = changeImpactConfigCache.get(repoRoot);
|
|
714
|
+
if (cached2 && cached2.sourceKey === loaded.sourceKey) {
|
|
715
|
+
return { config: cached2.config, sourceKey: loaded.sourceKey };
|
|
716
|
+
}
|
|
717
|
+
const config = loaded.sourceType === "repo_file" ? loaded.config ?? null : null;
|
|
718
|
+
changeImpactConfigCache.set(repoRoot, { sourceKey: loaded.sourceKey, config });
|
|
719
|
+
return { config, sourceKey: loaded.sourceKey };
|
|
720
|
+
}
|
|
438
721
|
async function detectDaemonBuildBehind(repo, submodules, options) {
|
|
439
722
|
const build = options.daemonBuildInfo ?? getDaemonBuildInfo();
|
|
440
723
|
if (!build.commit || build.commit === "unknown") return void 0;
|
|
724
|
+
const { config, sourceKey: configKey } = resolveChangeImpactConfigForRepo(repo.repoRoot, options);
|
|
725
|
+
const policy = resolveChangeImpactPolicy(config);
|
|
441
726
|
const scopes = [
|
|
442
727
|
{ scope: "root", repoPath: repo.repoRoot || repo.workspace }
|
|
443
728
|
];
|
|
@@ -451,11 +736,15 @@ async function detectDaemonBuildBehind(repo, submodules, options) {
|
|
|
451
736
|
const head = headResult.stdout.trim();
|
|
452
737
|
if (!head || head === build.commit) continue;
|
|
453
738
|
await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
options
|
|
458
|
-
|
|
739
|
+
const evalKey = `${repoPath}\0${build.commit}\0${head}\0${configKey}`;
|
|
740
|
+
let evaluated = changeImpactEvalCache.get(evalKey);
|
|
741
|
+
if (!evaluated) {
|
|
742
|
+
evaluated = await classifyDaemonBuildChange(repoPath, build.commit, options, policy);
|
|
743
|
+
changeImpactEvalCache.set(evalKey, evaluated);
|
|
744
|
+
}
|
|
745
|
+
const { isDaemonAffecting, affectedPackages } = evaluated;
|
|
746
|
+
const kind = isDaemonAffecting ? "daemon" : affectedPackages.length > 0 ? "web" : "none";
|
|
747
|
+
const target = policy.impactTargets[kind];
|
|
459
748
|
const scopeLabel = scope === "root" ? "workspace" : scope;
|
|
460
749
|
const benignDetail = affectedPackages.length > 0 ? `only web packages changed (${affectedPackages.join(", ")})` : "only non-runtime files changed (markers/docs)";
|
|
461
750
|
const warning = isDaemonAffecting ? `Live daemon was built from ${build.commitShort} which is behind ${scopeLabel} HEAD ${head.slice(0, 7)}. Merged code is NOT live until the daemon is rebuilt/redeployed and restarted \u2014 a local dist rebuild alone does not update a cloud daemon.` : `Live daemon was built from ${build.commitShort} which is behind ${scopeLabel} HEAD ${head.slice(0, 7)}, but ${benignDetail}. Daemon restart NOT required \u2014 redeploy the web app to reflect the change.`;
|
|
@@ -466,6 +755,8 @@ async function detectDaemonBuildBehind(repo, submodules, options) {
|
|
|
466
755
|
scope,
|
|
467
756
|
isDaemonAffecting,
|
|
468
757
|
...affectedPackages && affectedPackages.length > 0 ? { affectedPackages } : {},
|
|
758
|
+
recommendedAction: kind,
|
|
759
|
+
recommendedCommand: target.recommendedCommand,
|
|
469
760
|
warning
|
|
470
761
|
};
|
|
471
762
|
} catch {
|
|
@@ -729,14 +1020,17 @@ async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
|
|
|
729
1020
|
submodule.error = formatGitError(error);
|
|
730
1021
|
}
|
|
731
1022
|
}
|
|
732
|
-
var lastKnownGoodStatus,
|
|
1023
|
+
var lastKnownGoodStatus, changeImpactEvalCache, changeImpactConfigCache, DEFAULT_DAEMON_RUNTIME_PACKAGES, DEFAULT_WEB_ONLY_PACKAGES, DEFAULT_IMPACT_TARGETS;
|
|
733
1024
|
var init_git_status = __esm({
|
|
734
1025
|
"src/git/git-status.ts"() {
|
|
735
1026
|
"use strict";
|
|
736
1027
|
init_git_executor();
|
|
737
1028
|
init_build_info();
|
|
1029
|
+
init_change_impact_config();
|
|
738
1030
|
lastKnownGoodStatus = /* @__PURE__ */ new Map();
|
|
739
|
-
|
|
1031
|
+
changeImpactEvalCache = /* @__PURE__ */ new Map();
|
|
1032
|
+
changeImpactConfigCache = /* @__PURE__ */ new Map();
|
|
1033
|
+
DEFAULT_DAEMON_RUNTIME_PACKAGES = [
|
|
740
1034
|
"daemon-core",
|
|
741
1035
|
"daemon-standalone",
|
|
742
1036
|
"session-host-core",
|
|
@@ -746,13 +1040,24 @@ var init_git_status = __esm({
|
|
|
746
1040
|
"terminal-mux-cli",
|
|
747
1041
|
"ghostty-vt-node",
|
|
748
1042
|
"mcp-server"
|
|
749
|
-
]
|
|
750
|
-
|
|
1043
|
+
];
|
|
1044
|
+
DEFAULT_WEB_ONLY_PACKAGES = [
|
|
751
1045
|
"web-core",
|
|
752
1046
|
"web-standalone",
|
|
753
1047
|
"web-devconsole",
|
|
754
1048
|
"terminal-render-web"
|
|
755
|
-
]
|
|
1049
|
+
];
|
|
1050
|
+
DEFAULT_IMPACT_TARGETS = {
|
|
1051
|
+
daemon: {
|
|
1052
|
+
recommendedCommand: "Redeploy + restart the daemon (a local dist rebuild alone does not update a cloud daemon)."
|
|
1053
|
+
},
|
|
1054
|
+
web: {
|
|
1055
|
+
recommendedCommand: "Redeploy the web app (no daemon restart required)."
|
|
1056
|
+
},
|
|
1057
|
+
none: {
|
|
1058
|
+
recommendedCommand: "No action required."
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
756
1061
|
}
|
|
757
1062
|
});
|
|
758
1063
|
|
|
@@ -1311,25 +1616,25 @@ function ensureMachineId(config) {
|
|
|
1311
1616
|
}
|
|
1312
1617
|
function getConfigDir() {
|
|
1313
1618
|
const override = process.env.ADHDEV_CONFIG_DIR;
|
|
1314
|
-
const dir = override && override.trim() ? override.trim() : (0,
|
|
1315
|
-
if (!(0,
|
|
1316
|
-
(0,
|
|
1619
|
+
const dir = override && override.trim() ? override.trim() : (0, import_path2.join)((0, import_os.homedir)(), ".adhdev");
|
|
1620
|
+
if (!(0, import_fs2.existsSync)(dir)) {
|
|
1621
|
+
(0, import_fs2.mkdirSync)(dir, { recursive: true });
|
|
1317
1622
|
}
|
|
1318
1623
|
return dir;
|
|
1319
1624
|
}
|
|
1320
1625
|
function getDaemonDataDir() {
|
|
1321
|
-
const dir = (0,
|
|
1322
|
-
if (!(0,
|
|
1323
|
-
(0,
|
|
1626
|
+
const dir = (0, import_path2.join)(getConfigDir(), "daemon");
|
|
1627
|
+
if (!(0, import_fs2.existsSync)(dir)) {
|
|
1628
|
+
(0, import_fs2.mkdirSync)(dir, { recursive: true });
|
|
1324
1629
|
}
|
|
1325
1630
|
return dir;
|
|
1326
1631
|
}
|
|
1327
1632
|
function getConfigPath() {
|
|
1328
|
-
return (0,
|
|
1633
|
+
return (0, import_path2.join)(getConfigDir(), "config.json");
|
|
1329
1634
|
}
|
|
1330
1635
|
function migrateStateToStateFile(raw) {
|
|
1331
|
-
const statePath = (0,
|
|
1332
|
-
if ((0,
|
|
1636
|
+
const statePath = (0, import_path2.join)(getConfigDir(), "state.json");
|
|
1637
|
+
if ((0, import_fs2.existsSync)(statePath)) return;
|
|
1333
1638
|
const recentActivity = Array.isArray(raw.recentActivity) ? raw.recentActivity : [];
|
|
1334
1639
|
const savedProviderSessions = Array.isArray(raw.savedProviderSessions) ? raw.savedProviderSessions : [];
|
|
1335
1640
|
const legacySessionReads = isPlainObject(raw.recentSessionReads) ? raw.recentSessionReads : {};
|
|
@@ -1349,11 +1654,11 @@ function migrateStateToStateFile(raw) {
|
|
|
1349
1654
|
sessionReads: mergedReads,
|
|
1350
1655
|
sessionReadMarkers: cleanedMarkers
|
|
1351
1656
|
};
|
|
1352
|
-
(0,
|
|
1657
|
+
(0, import_fs2.writeFileSync)(statePath, JSON.stringify(state, null, 2), { encoding: "utf-8", mode: 384 });
|
|
1353
1658
|
}
|
|
1354
1659
|
function loadConfig() {
|
|
1355
1660
|
const configPath = getConfigPath();
|
|
1356
|
-
if (!(0,
|
|
1661
|
+
if (!(0, import_fs2.existsSync)(configPath)) {
|
|
1357
1662
|
const initialized = ensureMachineId({ ...DEFAULT_CONFIG });
|
|
1358
1663
|
try {
|
|
1359
1664
|
saveConfig(initialized.config);
|
|
@@ -1362,7 +1667,7 @@ function loadConfig() {
|
|
|
1362
1667
|
return initialized.config;
|
|
1363
1668
|
}
|
|
1364
1669
|
try {
|
|
1365
|
-
const raw = (0,
|
|
1670
|
+
const raw = (0, import_fs2.readFileSync)(configPath, "utf-8");
|
|
1366
1671
|
const parsed = JSON.parse(raw);
|
|
1367
1672
|
migrateStateToStateFile(parsed);
|
|
1368
1673
|
const normalizedInput = normalizeConfig(parsed);
|
|
@@ -1384,12 +1689,12 @@ function saveConfig(config) {
|
|
|
1384
1689
|
const configPath = getConfigPath();
|
|
1385
1690
|
const dir = getConfigDir();
|
|
1386
1691
|
const normalized = normalizeConfig(config);
|
|
1387
|
-
if (!(0,
|
|
1388
|
-
(0,
|
|
1692
|
+
if (!(0, import_fs2.existsSync)(dir)) {
|
|
1693
|
+
(0, import_fs2.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
1389
1694
|
}
|
|
1390
|
-
(0,
|
|
1695
|
+
(0, import_fs2.writeFileSync)(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
1391
1696
|
try {
|
|
1392
|
-
(0,
|
|
1697
|
+
(0, import_fs2.chmodSync)(configPath, 384);
|
|
1393
1698
|
} catch {
|
|
1394
1699
|
}
|
|
1395
1700
|
}
|
|
@@ -1416,13 +1721,13 @@ function isSetupComplete() {
|
|
|
1416
1721
|
function resetConfig() {
|
|
1417
1722
|
saveConfig({ ...DEFAULT_CONFIG });
|
|
1418
1723
|
}
|
|
1419
|
-
var import_os,
|
|
1724
|
+
var import_os, import_path2, import_fs2, import_crypto, DEFAULT_CONFIG, MACHINE_ID_PREFIX;
|
|
1420
1725
|
var init_config = __esm({
|
|
1421
1726
|
"src/config/config.ts"() {
|
|
1422
1727
|
"use strict";
|
|
1423
1728
|
import_os = require("os");
|
|
1424
|
-
|
|
1425
|
-
|
|
1729
|
+
import_path2 = require("path");
|
|
1730
|
+
import_fs2 = require("fs");
|
|
1426
1731
|
import_crypto = require("crypto");
|
|
1427
1732
|
DEFAULT_CONFIG = {
|
|
1428
1733
|
serverUrl: "https://api.adhf.dev",
|
|
@@ -1541,13 +1846,13 @@ __export(mesh_config_exports, {
|
|
|
1541
1846
|
updateNode: () => updateNode
|
|
1542
1847
|
});
|
|
1543
1848
|
function getMeshConfigPath() {
|
|
1544
|
-
return (0,
|
|
1849
|
+
return (0, import_path3.join)(getConfigDir(), "meshes.json");
|
|
1545
1850
|
}
|
|
1546
1851
|
function loadMeshConfig() {
|
|
1547
1852
|
const path42 = getMeshConfigPath();
|
|
1548
|
-
if (!(0,
|
|
1853
|
+
if (!(0, import_fs3.existsSync)(path42)) return { meshes: [] };
|
|
1549
1854
|
try {
|
|
1550
|
-
const raw = JSON.parse((0,
|
|
1855
|
+
const raw = JSON.parse((0, import_fs3.readFileSync)(path42, "utf-8"));
|
|
1551
1856
|
if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
|
|
1552
1857
|
const config = raw;
|
|
1553
1858
|
const migrated = migrateLoadedMeshConfig(config);
|
|
@@ -1597,7 +1902,7 @@ function normalizeCapabilityTags(value) {
|
|
|
1597
1902
|
}
|
|
1598
1903
|
function saveMeshConfig(config) {
|
|
1599
1904
|
const path42 = getMeshConfigPath();
|
|
1600
|
-
(0,
|
|
1905
|
+
(0, import_fs3.writeFileSync)(path42, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
|
|
1601
1906
|
}
|
|
1602
1907
|
function normalizeRepoIdentity(remoteUrl) {
|
|
1603
1908
|
let identity = remoteUrl.trim();
|
|
@@ -1957,12 +2262,12 @@ function updateNode(meshId, nodeId, opts) {
|
|
|
1957
2262
|
saveMeshConfig(config);
|
|
1958
2263
|
return node;
|
|
1959
2264
|
}
|
|
1960
|
-
var
|
|
2265
|
+
var import_fs3, import_path3, import_crypto3, SESSION_CLEANUP_MODES, SPAWNED_SESSION_VISIBILITY_MODES;
|
|
1961
2266
|
var init_mesh_config = __esm({
|
|
1962
2267
|
"src/config/mesh-config.ts"() {
|
|
1963
2268
|
"use strict";
|
|
1964
|
-
|
|
1965
|
-
|
|
2269
|
+
import_fs3 = require("fs");
|
|
2270
|
+
import_path3 = require("path");
|
|
1966
2271
|
import_crypto3 = require("crypto");
|
|
1967
2272
|
init_config();
|
|
1968
2273
|
init_repo_mesh_types();
|
|
@@ -2259,41 +2564,41 @@ function isIntentionalCleanupStopEntry(entry) {
|
|
|
2259
2564
|
return payload.intentional === true && (payload.reason === "operator_cleanup" || payload.intentionalStopReason === "operator_cleanup" || payload.source === "mesh_cleanup_sessions" || payload.source === "mesh_remove_node");
|
|
2260
2565
|
}
|
|
2261
2566
|
function getLedgerDir() {
|
|
2262
|
-
const dir = (0,
|
|
2263
|
-
if (!(0,
|
|
2264
|
-
(0,
|
|
2567
|
+
const dir = (0, import_path4.join)(getConfigDir(), LEDGER_DIR_NAME);
|
|
2568
|
+
if (!(0, import_fs4.existsSync)(dir)) {
|
|
2569
|
+
(0, import_fs4.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
2265
2570
|
}
|
|
2266
2571
|
return dir;
|
|
2267
2572
|
}
|
|
2268
2573
|
function getLedgerPath(meshId) {
|
|
2269
2574
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2270
|
-
return (0,
|
|
2575
|
+
return (0, import_path4.join)(getLedgerDir(), `${safe}.jsonl`);
|
|
2271
2576
|
}
|
|
2272
2577
|
function getRotatedPath(meshId, index) {
|
|
2273
2578
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2274
|
-
return (0,
|
|
2579
|
+
return (0, import_path4.join)(getLedgerDir(), `${safe}.${index}.jsonl`);
|
|
2275
2580
|
}
|
|
2276
2581
|
function getArchivePath(meshId) {
|
|
2277
2582
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2278
|
-
return (0,
|
|
2583
|
+
return (0, import_path4.join)(getLedgerDir(), `${safe}.archive.jsonl`);
|
|
2279
2584
|
}
|
|
2280
2585
|
function getRotatedArchivePath(meshId, index) {
|
|
2281
2586
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2282
|
-
return (0,
|
|
2587
|
+
return (0, import_path4.join)(getLedgerDir(), `${safe}.archive.${index}.jsonl`);
|
|
2283
2588
|
}
|
|
2284
2589
|
function getArchivedCountsPath(meshId) {
|
|
2285
2590
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2286
|
-
return (0,
|
|
2591
|
+
return (0, import_path4.join)(getLedgerDir(), `${safe}.archived-counts.json`);
|
|
2287
2592
|
}
|
|
2288
2593
|
function rotateArchiveFile(meshId, archivePath) {
|
|
2289
2594
|
let index = 1;
|
|
2290
|
-
while ((0,
|
|
2595
|
+
while ((0, import_fs4.existsSync)(getRotatedArchivePath(meshId, index))) {
|
|
2291
2596
|
index++;
|
|
2292
2597
|
if (index > 5) break;
|
|
2293
2598
|
}
|
|
2294
2599
|
if (index > 5) index = 5;
|
|
2295
2600
|
try {
|
|
2296
|
-
(0,
|
|
2601
|
+
(0, import_fs4.renameSync)(archivePath, getRotatedArchivePath(meshId, index));
|
|
2297
2602
|
} catch (e) {
|
|
2298
2603
|
process.stderr.write(`[adhdev-mesh] Archive rotation failed for mesh ${meshId}: ${e?.message || e}
|
|
2299
2604
|
`);
|
|
@@ -2301,9 +2606,9 @@ function rotateArchiveFile(meshId, archivePath) {
|
|
|
2301
2606
|
}
|
|
2302
2607
|
function readArchivedCounts(meshId) {
|
|
2303
2608
|
const path42 = getArchivedCountsPath(meshId);
|
|
2304
|
-
if (!(0,
|
|
2609
|
+
if (!(0, import_fs4.existsSync)(path42)) return { taskCompleted: 0, taskFailed: 0, taskStalled: 0, recoveryAttempted: 0, totalArchived: 0, lastArchivedAt: "" };
|
|
2305
2610
|
try {
|
|
2306
|
-
return JSON.parse((0,
|
|
2611
|
+
return JSON.parse((0, import_fs4.readFileSync)(path42, "utf-8"));
|
|
2307
2612
|
} catch {
|
|
2308
2613
|
return { taskCompleted: 0, taskFailed: 0, taskStalled: 0, recoveryAttempted: 0, totalArchived: 0, lastArchivedAt: "" };
|
|
2309
2614
|
}
|
|
@@ -2319,7 +2624,7 @@ function updateArchivedCounts(meshId, archived) {
|
|
|
2319
2624
|
counts.totalArchived += archived.length;
|
|
2320
2625
|
counts.lastArchivedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2321
2626
|
try {
|
|
2322
|
-
(0,
|
|
2627
|
+
(0, import_fs4.writeFileSync)(getArchivedCountsPath(meshId), JSON.stringify(counts), { encoding: "utf-8", mode: 384 });
|
|
2323
2628
|
} catch {
|
|
2324
2629
|
}
|
|
2325
2630
|
}
|
|
@@ -2342,7 +2647,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
2342
2647
|
}
|
|
2343
2648
|
function compactLedger(meshId) {
|
|
2344
2649
|
const filePath = getLedgerPath(meshId);
|
|
2345
|
-
if (!(0,
|
|
2650
|
+
if (!(0, import_fs4.existsSync)(filePath)) return { archivedCount: 0, retainedCount: 0 };
|
|
2346
2651
|
const cutoff = Date.now() - ARCHIVE_TERMINAL_OLDER_THAN_MS;
|
|
2347
2652
|
const entries = readLedgerEntries(meshId);
|
|
2348
2653
|
const keep = [];
|
|
@@ -2357,11 +2662,11 @@ function compactLedger(meshId) {
|
|
|
2357
2662
|
if (archive.length === 0) return { archivedCount: 0, retainedCount: keep.length };
|
|
2358
2663
|
const archivePath = getArchivePath(meshId);
|
|
2359
2664
|
try {
|
|
2360
|
-
if ((0,
|
|
2665
|
+
if ((0, import_fs4.existsSync)(archivePath) && (0, import_fs4.statSync)(archivePath).size > 50 * 1024 * 1024) {
|
|
2361
2666
|
rotateArchiveFile(meshId, archivePath);
|
|
2362
2667
|
}
|
|
2363
2668
|
const archiveLines = archive.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
2364
|
-
(0,
|
|
2669
|
+
(0, import_fs4.appendFileSync)(archivePath, archiveLines, { encoding: "utf-8", mode: 384 });
|
|
2365
2670
|
updateArchivedCounts(meshId, archive);
|
|
2366
2671
|
} catch (e) {
|
|
2367
2672
|
process.stderr.write(`[adhdev-mesh] Ledger archive write failed for mesh ${meshId}: ${e?.message || e}
|
|
@@ -2370,7 +2675,7 @@ function compactLedger(meshId) {
|
|
|
2370
2675
|
}
|
|
2371
2676
|
try {
|
|
2372
2677
|
const keepLines = keep.length ? keep.map((e) => JSON.stringify(e)).join("\n") + "\n" : "";
|
|
2373
|
-
(0,
|
|
2678
|
+
(0, import_fs4.writeFileSync)(filePath, keepLines, { encoding: "utf-8", mode: 384 });
|
|
2374
2679
|
invalidateLedgerCache(meshId);
|
|
2375
2680
|
} catch (e) {
|
|
2376
2681
|
process.stderr.write(`[adhdev-mesh] Ledger compaction rewrite failed for mesh ${meshId}: ${e?.message || e}
|
|
@@ -2507,9 +2812,9 @@ function appendLedgerEntry(meshId, partial) {
|
|
|
2507
2812
|
...partial
|
|
2508
2813
|
};
|
|
2509
2814
|
const filePath = getLedgerPath(meshId);
|
|
2510
|
-
if ((0,
|
|
2815
|
+
if ((0, import_fs4.existsSync)(filePath)) {
|
|
2511
2816
|
try {
|
|
2512
|
-
const stat2 = (0,
|
|
2817
|
+
const stat2 = (0, import_fs4.statSync)(filePath);
|
|
2513
2818
|
if (stat2.size >= MAX_FILE_SIZE_BYTES) {
|
|
2514
2819
|
rotateLedgerFile(meshId, filePath);
|
|
2515
2820
|
} else if (stat2.size >= COMPACT_THRESHOLD_BYTES) {
|
|
@@ -2534,7 +2839,7 @@ function appendLedgerEntry(meshId, partial) {
|
|
|
2534
2839
|
}
|
|
2535
2840
|
try {
|
|
2536
2841
|
const line = JSON.stringify(entry) + "\n";
|
|
2537
|
-
(0,
|
|
2842
|
+
(0, import_fs4.appendFileSync)(filePath, line, { encoding: "utf-8", mode: 384 });
|
|
2538
2843
|
invalidateLedgerCache(meshId);
|
|
2539
2844
|
meshLedgerEvents.emit("append", meshId, entry);
|
|
2540
2845
|
return entry;
|
|
@@ -2593,7 +2898,7 @@ function appendRemoteLedgerEntries(meshId, entries) {
|
|
|
2593
2898
|
}
|
|
2594
2899
|
try {
|
|
2595
2900
|
const lines = validEntries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
2596
|
-
(0,
|
|
2901
|
+
(0, import_fs4.appendFileSync)(ledgerPath, lines, { encoding: "utf-8", mode: 384 });
|
|
2597
2902
|
invalidateLedgerCache(meshId);
|
|
2598
2903
|
for (const entry of validEntries) {
|
|
2599
2904
|
meshLedgerEvents.emit("append", meshId, entry);
|
|
@@ -2605,10 +2910,10 @@ function appendRemoteLedgerEntries(meshId, entries) {
|
|
|
2605
2910
|
}
|
|
2606
2911
|
function readLedgerFile(meshId) {
|
|
2607
2912
|
const filePath = getLedgerPath(meshId);
|
|
2608
|
-
if (!(0,
|
|
2913
|
+
if (!(0, import_fs4.existsSync)(filePath)) return [];
|
|
2609
2914
|
let content;
|
|
2610
2915
|
try {
|
|
2611
|
-
content = (0,
|
|
2916
|
+
content = (0, import_fs4.readFileSync)(filePath, "utf-8");
|
|
2612
2917
|
} catch {
|
|
2613
2918
|
return [];
|
|
2614
2919
|
}
|
|
@@ -2869,24 +3174,24 @@ function getSessionRecoveryContext(meshId, opts) {
|
|
|
2869
3174
|
}
|
|
2870
3175
|
function rotateLedgerFile(meshId, currentPath) {
|
|
2871
3176
|
let index = 1;
|
|
2872
|
-
while ((0,
|
|
3177
|
+
while ((0, import_fs4.existsSync)(getRotatedPath(meshId, index))) {
|
|
2873
3178
|
index++;
|
|
2874
3179
|
if (index > 10) break;
|
|
2875
3180
|
}
|
|
2876
3181
|
if (index > 10) index = 10;
|
|
2877
3182
|
try {
|
|
2878
|
-
(0,
|
|
3183
|
+
(0, import_fs4.renameSync)(currentPath, getRotatedPath(meshId, index));
|
|
2879
3184
|
} catch (e) {
|
|
2880
3185
|
process.stderr.write(`[adhdev-mesh] Ledger rotation failed for mesh ${meshId}: ${e?.message || e}. File will continue to grow.
|
|
2881
3186
|
`);
|
|
2882
3187
|
}
|
|
2883
3188
|
}
|
|
2884
|
-
var
|
|
3189
|
+
var import_fs4, import_path4, import_crypto4, import_events, LEDGER_DIR_NAME, MAX_FILE_SIZE_BYTES, COMPACT_THRESHOLD_BYTES, ARCHIVE_TERMINAL_OLDER_THAN_MS, RECENT_FAILURE_WINDOW_MS, ARCHIVABLE_KINDS, DEFAULT_LEDGER_SLICE_LIMIT, MAX_LEDGER_SLICE_LIMIT, meshLedgerEvents, ledgerReadCache, LEDGER_CACHE_TTL_MS, ledgerImportStoreRef, ledgerImportDone;
|
|
2885
3190
|
var init_mesh_ledger = __esm({
|
|
2886
3191
|
"src/mesh/mesh-ledger.ts"() {
|
|
2887
3192
|
"use strict";
|
|
2888
|
-
|
|
2889
|
-
|
|
3193
|
+
import_fs4 = require("fs");
|
|
3194
|
+
import_path4 = require("path");
|
|
2890
3195
|
import_crypto4 = require("crypto");
|
|
2891
3196
|
init_config();
|
|
2892
3197
|
import_events = require("events");
|
|
@@ -3554,32 +3859,32 @@ function safeMeshId(meshId) {
|
|
|
3554
3859
|
return meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3555
3860
|
}
|
|
3556
3861
|
function legacyQueuePath(meshId) {
|
|
3557
|
-
return (0,
|
|
3862
|
+
return (0, import_path5.join)(getLedgerDir(), `${safeMeshId(meshId)}.queue.json`);
|
|
3558
3863
|
}
|
|
3559
3864
|
function meshRuntimeStorePath() {
|
|
3560
3865
|
const dir = getLedgerDir();
|
|
3561
|
-
const nextPath = (0,
|
|
3562
|
-
if ((0,
|
|
3563
|
-
const legacyPath = (0,
|
|
3564
|
-
if (!(0,
|
|
3866
|
+
const nextPath = (0, import_path5.join)(dir, "mesh-runtime.db");
|
|
3867
|
+
if ((0, import_fs5.existsSync)(nextPath)) return nextPath;
|
|
3868
|
+
const legacyPath = (0, import_path5.join)(dir, "beads.db");
|
|
3869
|
+
if (!(0, import_fs5.existsSync)(legacyPath)) return nextPath;
|
|
3565
3870
|
try {
|
|
3566
|
-
(0,
|
|
3871
|
+
(0, import_fs5.renameSync)(legacyPath, nextPath);
|
|
3567
3872
|
for (const suffix of ["-wal", "-shm"]) {
|
|
3568
3873
|
const legacyCompanion = `${legacyPath}${suffix}`;
|
|
3569
|
-
if ((0,
|
|
3570
|
-
(0,
|
|
3874
|
+
if ((0, import_fs5.existsSync)(legacyCompanion)) {
|
|
3875
|
+
(0, import_fs5.renameSync)(legacyCompanion, `${nextPath}${suffix}`);
|
|
3571
3876
|
}
|
|
3572
3877
|
}
|
|
3573
3878
|
} catch {
|
|
3574
3879
|
}
|
|
3575
3880
|
return nextPath;
|
|
3576
3881
|
}
|
|
3577
|
-
var
|
|
3882
|
+
var import_fs5, import_path5, import_module, import_meta, DatabaseCtor, MeshRuntimeStore;
|
|
3578
3883
|
var init_mesh_runtime_store = __esm({
|
|
3579
3884
|
"src/mesh/mesh-runtime-store.ts"() {
|
|
3580
3885
|
"use strict";
|
|
3581
|
-
|
|
3582
|
-
|
|
3886
|
+
import_fs5 = require("fs");
|
|
3887
|
+
import_path5 = require("path");
|
|
3583
3888
|
import_module = require("module");
|
|
3584
3889
|
init_mesh_ledger();
|
|
3585
3890
|
init_mesh_work_queue();
|
|
@@ -3595,8 +3900,8 @@ var init_mesh_runtime_store = __esm({
|
|
|
3595
3900
|
static WAL_MAX_BYTES = 50 * 1024 * 1024;
|
|
3596
3901
|
// 50 MB
|
|
3597
3902
|
constructor(dbPath) {
|
|
3598
|
-
const dir = (0,
|
|
3599
|
-
if (!(0,
|
|
3903
|
+
const dir = (0, import_path5.dirname)(dbPath);
|
|
3904
|
+
if (!(0, import_fs5.existsSync)(dir)) (0, import_fs5.mkdirSync)(dir, { recursive: true });
|
|
3600
3905
|
this.dbPath = dbPath;
|
|
3601
3906
|
this.db = new (loadDatabaseCtor())(dbPath);
|
|
3602
3907
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -3851,8 +4156,8 @@ var init_mesh_runtime_store = __esm({
|
|
|
3851
4156
|
this.walWriteCounter = 0;
|
|
3852
4157
|
try {
|
|
3853
4158
|
const walPath = `${this.dbPath}-wal`;
|
|
3854
|
-
if (!(0,
|
|
3855
|
-
const size = (0,
|
|
4159
|
+
if (!(0, import_fs5.existsSync)(walPath)) return;
|
|
4160
|
+
const size = (0, import_fs5.statSync)(walPath).size;
|
|
3856
4161
|
if (size < _MeshRuntimeStore.WAL_MAX_BYTES) return;
|
|
3857
4162
|
process.stderr.write(
|
|
3858
4163
|
`[adhdev-mesh] WAL file ${Math.round(size / 1024 / 1024)}MB exceeds threshold; forcing checkpoint
|
|
@@ -3868,9 +4173,9 @@ var init_mesh_runtime_store = __esm({
|
|
|
3868
4173
|
const count = this.db.prepare("SELECT COUNT(*) AS count FROM mesh_queue WHERE mesh_id = ?").get(meshId);
|
|
3869
4174
|
if (count.count > 0) return;
|
|
3870
4175
|
const path42 = legacyQueuePath(meshId);
|
|
3871
|
-
if (!(0,
|
|
4176
|
+
if (!(0, import_fs5.existsSync)(path42)) return;
|
|
3872
4177
|
try {
|
|
3873
|
-
const entries = JSON.parse((0,
|
|
4178
|
+
const entries = JSON.parse((0, import_fs5.readFileSync)(path42, "utf-8"));
|
|
3874
4179
|
if (!Array.isArray(entries)) return;
|
|
3875
4180
|
const insert = this.db.prepare(`
|
|
3876
4181
|
INSERT OR REPLACE INTO mesh_queue (
|
|
@@ -6976,6 +7281,410 @@ var init_dist = __esm({
|
|
|
6976
7281
|
}
|
|
6977
7282
|
});
|
|
6978
7283
|
|
|
7284
|
+
// src/mesh/mesh-active-work.ts
|
|
7285
|
+
function readString6(value) {
|
|
7286
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
7287
|
+
}
|
|
7288
|
+
function summarizeMessage(message) {
|
|
7289
|
+
const oneLine2 = message.replace(/\s+/g, " ").trim();
|
|
7290
|
+
const title = oneLine2.length > 96 ? `${oneLine2.slice(0, 93)}...` : oneLine2;
|
|
7291
|
+
return { title: title || "(untitled task)", summary: oneLine2 };
|
|
7292
|
+
}
|
|
7293
|
+
function elapsedSince(value, now) {
|
|
7294
|
+
const started = value ? new Date(value).getTime() : Number.NaN;
|
|
7295
|
+
return Number.isFinite(started) ? Math.max(0, now - started) : 0;
|
|
7296
|
+
}
|
|
7297
|
+
function sessionStatusFromNodes(nodes, nodeId, sessionId) {
|
|
7298
|
+
if (!Array.isArray(nodes)) return {};
|
|
7299
|
+
if (!nodeId) return { staleReason: "direct task has no node id" };
|
|
7300
|
+
const node = nodes.find((item) => meshNodeIdMatches(item, nodeId));
|
|
7301
|
+
if (!node) return { staleReason: "direct task node is no longer in the live mesh" };
|
|
7302
|
+
if (!sessionId) return {};
|
|
7303
|
+
const candidates = [];
|
|
7304
|
+
for (const value of [
|
|
7305
|
+
node.sessions,
|
|
7306
|
+
node.activeSessions,
|
|
7307
|
+
node.active_sessions,
|
|
7308
|
+
node.activeSessionDetails,
|
|
7309
|
+
node.active_session_details,
|
|
7310
|
+
node.sessionDetails,
|
|
7311
|
+
node.session_details,
|
|
7312
|
+
node.lastProbe?.sessions,
|
|
7313
|
+
node.last_probe?.sessions,
|
|
7314
|
+
node.lastProbe?.status?.sessions,
|
|
7315
|
+
node.last_probe?.status?.sessions
|
|
7316
|
+
]) {
|
|
7317
|
+
if (Array.isArray(value)) candidates.push(...value);
|
|
7318
|
+
}
|
|
7319
|
+
for (const value of [node.activeSession, node.active_session, node.currentSession, node.current_session, node.runtimeSession, node.runtime_session, node.session]) {
|
|
7320
|
+
if (value && typeof value === "object") candidates.push(value);
|
|
7321
|
+
}
|
|
7322
|
+
const session = candidates.find((item) => {
|
|
7323
|
+
if (typeof item === "string") return item === sessionId;
|
|
7324
|
+
const id = readString6(item?.id) || readString6(item?.sessionId) || readString6(item?.session_id) || readString6(item?.runtimeSessionId) || readString6(item?.instanceId);
|
|
7325
|
+
return id === sessionId;
|
|
7326
|
+
});
|
|
7327
|
+
if (!session) return { staleReason: "direct task session is not present in live session records" };
|
|
7328
|
+
if (typeof session === "string") return {};
|
|
7329
|
+
const raw = `${readString6(session.status) || ""} ${readString6(session.lifecycle) || ""} ${readString6(session.state) || ""} ${readString6(session.activeChat?.status) || ""}`.toLowerCase();
|
|
7330
|
+
if (raw.includes("approval")) return { status: "awaiting_approval" };
|
|
7331
|
+
if (raw.includes("generating") || raw.includes("running") || raw.includes("busy")) return { status: "generating" };
|
|
7332
|
+
if (raw.includes("failed") || raw.includes("stopped") || raw.includes("terminated") || raw.includes("exited")) return { status: "failed" };
|
|
7333
|
+
if (raw.includes("idle") || raw.includes("waiting_input") || raw.includes("ready")) return { status: "idle" };
|
|
7334
|
+
return {};
|
|
7335
|
+
}
|
|
7336
|
+
function isDirectDispatch(entry) {
|
|
7337
|
+
if (entry.kind !== "task_dispatched") return false;
|
|
7338
|
+
const payload = entry.payload || {};
|
|
7339
|
+
if (payload.source === "direct") return true;
|
|
7340
|
+
const via = readString6(payload.via);
|
|
7341
|
+
return Boolean(via && DIRECT_DISPATCH_VIA.has(via) && payload.source !== "queue");
|
|
7342
|
+
}
|
|
7343
|
+
function directDispatchTaskId(entry) {
|
|
7344
|
+
return readString6(entry.payload?.taskId) || entry.id;
|
|
7345
|
+
}
|
|
7346
|
+
function terminalMatchesDispatch(terminal, dispatch, taskId) {
|
|
7347
|
+
const terminalTaskId = readString6(terminal.payload?.taskId);
|
|
7348
|
+
if (terminalTaskId && terminalTaskId === taskId) return true;
|
|
7349
|
+
if (terminalTaskId && terminalTaskId !== taskId) return false;
|
|
7350
|
+
if (dispatch.sessionId && terminal.sessionId === dispatch.sessionId) return true;
|
|
7351
|
+
return Boolean(dispatch.nodeId && terminal.nodeId === dispatch.nodeId && !dispatch.sessionId);
|
|
7352
|
+
}
|
|
7353
|
+
function statusFromTerminal(entry) {
|
|
7354
|
+
if (entry.kind === "task_approval_needed") return "awaiting_approval";
|
|
7355
|
+
if (entry.kind === "task_completed") return "idle";
|
|
7356
|
+
return "failed";
|
|
7357
|
+
}
|
|
7358
|
+
function buildMeshActiveWorkSummary(activeWork) {
|
|
7359
|
+
const statusCounts = {
|
|
7360
|
+
pending: 0,
|
|
7361
|
+
assigned: 0,
|
|
7362
|
+
generating: 0,
|
|
7363
|
+
idle: 0,
|
|
7364
|
+
failed: 0,
|
|
7365
|
+
awaiting_approval: 0
|
|
7366
|
+
};
|
|
7367
|
+
const sourceCounts = { queue: 0, direct: 0 };
|
|
7368
|
+
for (const item of activeWork) {
|
|
7369
|
+
sourceCounts[item.source] += 1;
|
|
7370
|
+
statusCounts[item.status] += 1;
|
|
7371
|
+
}
|
|
7372
|
+
const staleDirectCount = activeWork.filter((item) => item.source === "direct" && item.staleReason).length;
|
|
7373
|
+
const staleDirectUnacknowledgedCount = activeWork.filter((item) => item.source === "direct" && item.staleDispatchUnacknowledged).length;
|
|
7374
|
+
return {
|
|
7375
|
+
totalActiveCount: activeWork.length,
|
|
7376
|
+
queueActiveCount: sourceCounts.queue,
|
|
7377
|
+
directActiveCount: sourceCounts.direct,
|
|
7378
|
+
awaitingApprovalCount: statusCounts.awaiting_approval,
|
|
7379
|
+
generatingCount: statusCounts.generating,
|
|
7380
|
+
failedCount: statusCounts.failed,
|
|
7381
|
+
idleCount: statusCounts.idle,
|
|
7382
|
+
sourceCounts,
|
|
7383
|
+
statusCounts,
|
|
7384
|
+
staleDirectCount,
|
|
7385
|
+
...staleDirectUnacknowledgedCount > 0 ? { staleDirectUnacknowledgedCount } : {},
|
|
7386
|
+
...staleDirectCount > 0 ? { staleDirectNote: "Stale direct records are orphaned ledger entries whose node/session no longer exists. They are historical recovery evidence only \u2014 not active or unresolved work. The queue (source: queue) is authoritative for pending/assigned tasks." } : {}
|
|
7387
|
+
};
|
|
7388
|
+
}
|
|
7389
|
+
function buildMeshActiveWork(opts) {
|
|
7390
|
+
const now = opts.now ?? Date.now();
|
|
7391
|
+
const records = [];
|
|
7392
|
+
const staleDirectWork = [];
|
|
7393
|
+
const terminalDirectWork = [];
|
|
7394
|
+
for (const task of opts.queue || []) {
|
|
7395
|
+
if (task.status !== "pending" && task.status !== "assigned") continue;
|
|
7396
|
+
const { title, summary: summary2 } = summarizeMessage(task.message || "");
|
|
7397
|
+
records.push({
|
|
7398
|
+
taskId: task.id,
|
|
7399
|
+
source: "queue",
|
|
7400
|
+
status: task.status,
|
|
7401
|
+
nodeId: task.assignedNodeId || task.targetNodeId,
|
|
7402
|
+
sessionId: task.assignedSessionId || task.targetSessionId,
|
|
7403
|
+
taskTitle: title,
|
|
7404
|
+
taskSummary: summary2,
|
|
7405
|
+
message: task.message,
|
|
7406
|
+
taskMode: task.taskMode,
|
|
7407
|
+
createdAt: task.createdAt,
|
|
7408
|
+
updatedAt: task.updatedAt,
|
|
7409
|
+
dispatchedAt: task.dispatchTimestamp,
|
|
7410
|
+
elapsedMs: elapsedSince(task.dispatchTimestamp || task.createdAt, now)
|
|
7411
|
+
});
|
|
7412
|
+
}
|
|
7413
|
+
if (opts.directDispatches !== void 0) {
|
|
7414
|
+
const dbTaskIds = new Set(opts.directDispatches.map((d) => d.taskId));
|
|
7415
|
+
for (const dispatch of opts.directDispatches) {
|
|
7416
|
+
const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId ?? void 0, dispatch.sessionId ?? void 0);
|
|
7417
|
+
const dbStatus = dispatch.status;
|
|
7418
|
+
const isTerminal = dbStatus === "completed" || dbStatus === "failed" || dbStatus === "stale";
|
|
7419
|
+
const status = isTerminal ? dbStatus === "completed" ? "idle" : "failed" : live.status || (dbStatus === "acked" ? "generating" : "assigned");
|
|
7420
|
+
const isNoTransition = !isTerminal && !live.status;
|
|
7421
|
+
const isIdleUnacknowledged = status === "idle" && !isTerminal;
|
|
7422
|
+
const ledgerOnlyStaleReason = !isTerminal && (isIdleUnacknowledged || isNoTransition || dispatch.dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
|
|
7423
|
+
const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
|
|
7424
|
+
const { title, summary: summary2 } = summarizeMessage(dispatch.message || "");
|
|
7425
|
+
const record = {
|
|
7426
|
+
taskId: dispatch.taskId,
|
|
7427
|
+
source: "direct",
|
|
7428
|
+
status,
|
|
7429
|
+
nodeId: dispatch.nodeId ?? void 0,
|
|
7430
|
+
sessionId: dispatch.sessionId ?? void 0,
|
|
7431
|
+
providerType: dispatch.providerType ?? void 0,
|
|
7432
|
+
taskTitle: title,
|
|
7433
|
+
taskSummary: summary2,
|
|
7434
|
+
message: dispatch.message,
|
|
7435
|
+
taskMode: dispatch.taskMode ?? void 0,
|
|
7436
|
+
createdAt: dispatch.dispatchedAt,
|
|
7437
|
+
updatedAt: dispatch.updatedAt,
|
|
7438
|
+
dispatchedAt: dispatch.dispatchedAt,
|
|
7439
|
+
elapsedMs: elapsedSince(dispatch.dispatchedAt, now),
|
|
7440
|
+
terminal: isTerminal,
|
|
7441
|
+
terminalKind: isTerminal ? dbStatus === "completed" ? "task_completed" : "task_failed" : void 0,
|
|
7442
|
+
terminalAt: isTerminal ? dispatch.updatedAt : void 0,
|
|
7443
|
+
staleReason: live.staleReason || ledgerOnlyStaleReason,
|
|
7444
|
+
...isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}
|
|
7445
|
+
};
|
|
7446
|
+
if (isTerminal) {
|
|
7447
|
+
terminalDirectWork.push(record);
|
|
7448
|
+
if (opts.includeTerminalDirect !== true) continue;
|
|
7449
|
+
}
|
|
7450
|
+
if ((live.staleReason || ledgerOnlyStaleReason) && !isTerminal) {
|
|
7451
|
+
staleDirectWork.push(record);
|
|
7452
|
+
continue;
|
|
7453
|
+
}
|
|
7454
|
+
records.push(record);
|
|
7455
|
+
}
|
|
7456
|
+
const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
7457
|
+
const terminals = ledgerEntries.filter((entry) => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === "task_approval_needed");
|
|
7458
|
+
for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
|
|
7459
|
+
const taskId = directDispatchTaskId(dispatch);
|
|
7460
|
+
if (dbTaskIds.has(taskId)) continue;
|
|
7461
|
+
const terminal = terminals.filter((entry) => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime()).find((entry) => terminalMatchesDispatch(entry, dispatch, taskId));
|
|
7462
|
+
const terminalStatus = terminal ? statusFromTerminal(terminal) : void 0;
|
|
7463
|
+
const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
|
|
7464
|
+
const status = terminalStatus || live.status || "assigned";
|
|
7465
|
+
const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
|
|
7466
|
+
const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
|
|
7467
|
+
const isNoTransition = !terminalStatus && !live.status;
|
|
7468
|
+
const isIdleUnacknowledged = status === "idle";
|
|
7469
|
+
const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
|
|
7470
|
+
const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
|
|
7471
|
+
const { title, summary: summary2 } = summarizeMessage(message);
|
|
7472
|
+
const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
|
|
7473
|
+
const record = {
|
|
7474
|
+
taskId,
|
|
7475
|
+
source: "direct",
|
|
7476
|
+
status,
|
|
7477
|
+
nodeId: dispatch.nodeId,
|
|
7478
|
+
sessionId: dispatch.sessionId,
|
|
7479
|
+
providerType: dispatch.providerType || readString6(dispatch.payload?.providerType),
|
|
7480
|
+
taskTitle: readString6(dispatch.payload?.taskTitle) || title,
|
|
7481
|
+
taskSummary: readString6(dispatch.payload?.taskSummary) || summary2,
|
|
7482
|
+
message,
|
|
7483
|
+
taskMode: readString6(dispatch.payload?.taskMode),
|
|
7484
|
+
createdAt: dispatch.timestamp,
|
|
7485
|
+
updatedAt: terminal?.timestamp || dispatch.timestamp,
|
|
7486
|
+
dispatchedAt: dispatch.timestamp,
|
|
7487
|
+
elapsedMs: elapsedSince(dispatch.timestamp, now),
|
|
7488
|
+
terminal: terminalRow,
|
|
7489
|
+
terminalKind: terminal?.kind,
|
|
7490
|
+
terminalAt: terminal?.timestamp,
|
|
7491
|
+
staleReason: live.staleReason || ledgerOnlyStaleReason,
|
|
7492
|
+
...isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}
|
|
7493
|
+
};
|
|
7494
|
+
if (terminalRow) {
|
|
7495
|
+
terminalDirectWork.push(record);
|
|
7496
|
+
if (opts.includeTerminalDirect !== true) continue;
|
|
7497
|
+
}
|
|
7498
|
+
if ((live.staleReason || ledgerOnlyStaleReason) && !terminalRow) {
|
|
7499
|
+
staleDirectWork.push(record);
|
|
7500
|
+
continue;
|
|
7501
|
+
}
|
|
7502
|
+
records.push(record);
|
|
7503
|
+
}
|
|
7504
|
+
} else {
|
|
7505
|
+
const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
7506
|
+
const terminals = ledgerEntries.filter((entry) => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === "task_approval_needed");
|
|
7507
|
+
for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
|
|
7508
|
+
const taskId = directDispatchTaskId(dispatch);
|
|
7509
|
+
const terminal = terminals.filter((entry) => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime()).find((entry) => terminalMatchesDispatch(entry, dispatch, taskId));
|
|
7510
|
+
const terminalStatus = terminal ? statusFromTerminal(terminal) : void 0;
|
|
7511
|
+
const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
|
|
7512
|
+
const status = terminalStatus || live.status || "assigned";
|
|
7513
|
+
const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
|
|
7514
|
+
const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
|
|
7515
|
+
const isNoTransition = !terminalStatus && !live.status;
|
|
7516
|
+
const isIdleUnacknowledged = status === "idle";
|
|
7517
|
+
const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
|
|
7518
|
+
const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
|
|
7519
|
+
const { title, summary: summary2 } = summarizeMessage(message);
|
|
7520
|
+
const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
|
|
7521
|
+
const record = {
|
|
7522
|
+
taskId,
|
|
7523
|
+
source: "direct",
|
|
7524
|
+
status,
|
|
7525
|
+
nodeId: dispatch.nodeId,
|
|
7526
|
+
sessionId: dispatch.sessionId,
|
|
7527
|
+
providerType: dispatch.providerType || readString6(dispatch.payload?.providerType),
|
|
7528
|
+
taskTitle: readString6(dispatch.payload?.taskTitle) || title,
|
|
7529
|
+
taskSummary: readString6(dispatch.payload?.taskSummary) || summary2,
|
|
7530
|
+
message,
|
|
7531
|
+
taskMode: readString6(dispatch.payload?.taskMode),
|
|
7532
|
+
createdAt: dispatch.timestamp,
|
|
7533
|
+
updatedAt: terminal?.timestamp || dispatch.timestamp,
|
|
7534
|
+
dispatchedAt: dispatch.timestamp,
|
|
7535
|
+
elapsedMs: elapsedSince(dispatch.timestamp, now),
|
|
7536
|
+
terminal: terminalRow,
|
|
7537
|
+
terminalKind: terminal?.kind,
|
|
7538
|
+
terminalAt: terminal?.timestamp,
|
|
7539
|
+
staleReason: live.staleReason || ledgerOnlyStaleReason,
|
|
7540
|
+
...isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}
|
|
7541
|
+
};
|
|
7542
|
+
if (terminalRow) {
|
|
7543
|
+
terminalDirectWork.push(record);
|
|
7544
|
+
if (opts.includeTerminalDirect !== true) continue;
|
|
7545
|
+
}
|
|
7546
|
+
if ((live.staleReason || ledgerOnlyStaleReason) && !terminalRow) {
|
|
7547
|
+
staleDirectWork.push(record);
|
|
7548
|
+
continue;
|
|
7549
|
+
}
|
|
7550
|
+
records.push(record);
|
|
7551
|
+
}
|
|
7552
|
+
}
|
|
7553
|
+
records.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
7554
|
+
staleDirectWork.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
7555
|
+
terminalDirectWork.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
7556
|
+
const summary = buildMeshActiveWorkSummary(records);
|
|
7557
|
+
summary.staleDirectCount = staleDirectWork.length;
|
|
7558
|
+
const unacknowledgedCount = staleDirectWork.filter((r) => r.staleDispatchUnacknowledged).length;
|
|
7559
|
+
if (unacknowledgedCount > 0) {
|
|
7560
|
+
summary.staleDirectUnacknowledgedCount = unacknowledgedCount;
|
|
7561
|
+
}
|
|
7562
|
+
const staleDirectWorkNote = staleDirectWork.length > 0 ? unacknowledgedCount > 0 && unacknowledgedCount === staleDirectWork.length ? `${unacknowledgedCount} direct dispatch(es) were not acknowledged by the target session \u2014 the session received the agent_command but never transitioned to generating. This is a fresh dispatch failure, not historical noise. Recovery: launch a fresh session on the same node and retry the task, or use mesh_enqueue_task for queue-based assignment.` : unacknowledgedCount > 0 ? `${unacknowledgedCount} of ${staleDirectWork.length} stale direct record(s) are fresh unacknowledged dispatch failures (session still live but never transitioned to generating); the rest are orphaned historical entries whose node/session no longer exists. Fresh unacknowledged dispatches need recovery: launch a fresh session and retry. Orphaned entries are historical evidence only \u2014 not active or unresolved work.` : "These are orphaned ledger entries whose original node or session no longer exists in the live mesh. They are historical/recovery evidence only \u2014 not active or unresolved work. Do not treat staleDirectCount as a status mismatch; use the queue (source: queue) as authoritative for pending/assigned tasks." : void 0;
|
|
7563
|
+
if (staleDirectWorkNote) {
|
|
7564
|
+
summary.staleDirectNote = staleDirectWorkNote;
|
|
7565
|
+
}
|
|
7566
|
+
return { activeWork: records, staleDirectWork, staleDirectWorkNote, terminalDirectWork, summary };
|
|
7567
|
+
}
|
|
7568
|
+
function classifyStaleDirectForPrune(record, opts = {}) {
|
|
7569
|
+
if (record.staleDispatchUnacknowledged === true) return "preserve_unacknowledged";
|
|
7570
|
+
if (record.terminal === true) return opts.includeTerminal ? "prunable_terminal" : "preserve_active";
|
|
7571
|
+
if (record.staleReason && PRUNABLE_ORPHAN_STALE_REASONS.has(record.staleReason)) return "prunable_orphan";
|
|
7572
|
+
return "preserve_active";
|
|
7573
|
+
}
|
|
7574
|
+
function pruneStaleDirectDispatches(opts) {
|
|
7575
|
+
const now = opts.now ?? Date.now();
|
|
7576
|
+
const includeTerminal = opts.includeTerminal === true;
|
|
7577
|
+
const execute = opts.execute === true;
|
|
7578
|
+
const minAgeMs = Math.max(0, opts.minAgeMs ?? 0);
|
|
7579
|
+
const activeWorkEvidence = buildMeshActiveWork({
|
|
7580
|
+
meshId: opts.meshId,
|
|
7581
|
+
queue: opts.queue,
|
|
7582
|
+
ledgerEntries: opts.ledgerEntries,
|
|
7583
|
+
directDispatches: opts.directDispatches,
|
|
7584
|
+
nodes: opts.nodes,
|
|
7585
|
+
now,
|
|
7586
|
+
includeTerminalDirect: includeTerminal
|
|
7587
|
+
});
|
|
7588
|
+
const candidates = [
|
|
7589
|
+
...activeWorkEvidence.staleDirectWork,
|
|
7590
|
+
...includeTerminal ? activeWorkEvidence.terminalDirectWork : []
|
|
7591
|
+
];
|
|
7592
|
+
const storeTaskIds = new Set(opts.directDispatches.map((d) => d.taskId));
|
|
7593
|
+
const prunable = [];
|
|
7594
|
+
const skippedTooYoung = [];
|
|
7595
|
+
const preservedUnacknowledged = [];
|
|
7596
|
+
const preservedLedgerOnly = [];
|
|
7597
|
+
const preservedNotOrphan = [];
|
|
7598
|
+
for (const record of candidates) {
|
|
7599
|
+
const classification = classifyStaleDirectForPrune(record, { includeTerminal });
|
|
7600
|
+
if (classification === "preserve_unacknowledged") {
|
|
7601
|
+
preservedUnacknowledged.push(record);
|
|
7602
|
+
continue;
|
|
7603
|
+
}
|
|
7604
|
+
if (classification === "preserve_active") {
|
|
7605
|
+
preservedNotOrphan.push(record);
|
|
7606
|
+
continue;
|
|
7607
|
+
}
|
|
7608
|
+
if (!storeTaskIds.has(record.taskId)) {
|
|
7609
|
+
preservedLedgerOnly.push(record);
|
|
7610
|
+
continue;
|
|
7611
|
+
}
|
|
7612
|
+
if (minAgeMs > 0) {
|
|
7613
|
+
const ageRef = record.dispatchedAt || record.createdAt;
|
|
7614
|
+
const ageMs = elapsedSince(ageRef, now);
|
|
7615
|
+
if (ageMs < minAgeMs) {
|
|
7616
|
+
skippedTooYoung.push(record);
|
|
7617
|
+
continue;
|
|
7618
|
+
}
|
|
7619
|
+
}
|
|
7620
|
+
prunable.push(record);
|
|
7621
|
+
}
|
|
7622
|
+
let prunedCount = 0;
|
|
7623
|
+
if (execute && prunable.length) {
|
|
7624
|
+
prunedCount = deleteDirectDispatchesByTaskId(opts.meshId, prunable.map((r) => r.taskId));
|
|
7625
|
+
appendLedgerEntry(opts.meshId, {
|
|
7626
|
+
kind: "direct_dispatch_pruned",
|
|
7627
|
+
payload: {
|
|
7628
|
+
source: opts.source || "prune_stale_direct",
|
|
7629
|
+
prunedCount,
|
|
7630
|
+
taskIds: prunable.map((r) => r.taskId),
|
|
7631
|
+
reasons: Array.from(new Set(prunable.map((r) => r.staleReason || (r.terminal ? "terminal" : "unknown"))))
|
|
7632
|
+
}
|
|
7633
|
+
});
|
|
7634
|
+
}
|
|
7635
|
+
return {
|
|
7636
|
+
mode: execute ? "execute" : "dry_run",
|
|
7637
|
+
includeTerminal,
|
|
7638
|
+
candidateCount: candidates.length,
|
|
7639
|
+
prunable,
|
|
7640
|
+
prunedCount,
|
|
7641
|
+
skippedTooYoung,
|
|
7642
|
+
preservedUnacknowledged,
|
|
7643
|
+
preservedLedgerOnly,
|
|
7644
|
+
preservedNotOrphan
|
|
7645
|
+
};
|
|
7646
|
+
}
|
|
7647
|
+
function buildCompactStaleDirectWorkSummary(staleDirectWork, opts = {}) {
|
|
7648
|
+
const sampleLimit = Math.max(0, Math.min(10, Math.floor(opts.sampleLimit ?? 3)));
|
|
7649
|
+
const reasonCounts = {};
|
|
7650
|
+
for (const entry of staleDirectWork) {
|
|
7651
|
+
const reason = entry.staleReason || "unknown";
|
|
7652
|
+
reasonCounts[reason] = (reasonCounts[reason] || 0) + 1;
|
|
7653
|
+
}
|
|
7654
|
+
return {
|
|
7655
|
+
count: staleDirectWork.length,
|
|
7656
|
+
sampleLimit,
|
|
7657
|
+
sample: staleDirectWork.slice(0, sampleLimit).map((entry) => ({
|
|
7658
|
+
taskId: entry.taskId,
|
|
7659
|
+
status: entry.status,
|
|
7660
|
+
nodeId: entry.nodeId,
|
|
7661
|
+
sessionId: entry.sessionId,
|
|
7662
|
+
taskTitle: entry.taskTitle,
|
|
7663
|
+
createdAt: entry.createdAt,
|
|
7664
|
+
staleReason: entry.staleReason
|
|
7665
|
+
})),
|
|
7666
|
+
reasonCounts,
|
|
7667
|
+
detailHint: opts.detailHint || "Stale direct records are historical recovery evidence only. Use mesh_task_history for full ledger details, or request includeStaleDirectWorkDetails when supported by the caller.",
|
|
7668
|
+
...opts.note ? { note: opts.note } : {}
|
|
7669
|
+
};
|
|
7670
|
+
}
|
|
7671
|
+
var DIRECT_DISPATCH_VIA, TERMINAL_LEDGER_KINDS, PRUNABLE_ORPHAN_STALE_REASONS;
|
|
7672
|
+
var init_mesh_active_work = __esm({
|
|
7673
|
+
"src/mesh/mesh-active-work.ts"() {
|
|
7674
|
+
"use strict";
|
|
7675
|
+
init_mesh_ledger();
|
|
7676
|
+
init_mesh_work_queue();
|
|
7677
|
+
init_dist();
|
|
7678
|
+
DIRECT_DISPATCH_VIA = /* @__PURE__ */ new Set(["p2p_direct", "local_direct", "mesh_send_task"]);
|
|
7679
|
+
TERMINAL_LEDGER_KINDS = /* @__PURE__ */ new Set(["task_completed", "task_failed", "task_stalled"]);
|
|
7680
|
+
PRUNABLE_ORPHAN_STALE_REASONS = /* @__PURE__ */ new Set([
|
|
7681
|
+
"direct task node is no longer in the live mesh",
|
|
7682
|
+
"direct task session is not present in live session records",
|
|
7683
|
+
"direct task has no node id"
|
|
7684
|
+
]);
|
|
7685
|
+
}
|
|
7686
|
+
});
|
|
7687
|
+
|
|
6979
7688
|
// src/mesh/mesh-events-utils.ts
|
|
6980
7689
|
function readNonEmptyString2(value) {
|
|
6981
7690
|
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
@@ -7030,8 +7739,8 @@ function formatCompletionMetadata(event) {
|
|
|
7030
7739
|
function buildMeshSystemMessage(args) {
|
|
7031
7740
|
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
7032
7741
|
if (args.event === "agent:generating_completed") {
|
|
7033
|
-
if (args.metadataEvent.source === "
|
|
7034
|
-
return `[System] ${args.nodeLabel} already has completion evidence${metadata}. The
|
|
7742
|
+
if (args.metadataEvent.source === "no_progress_reconciliation") {
|
|
7743
|
+
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.`;
|
|
7035
7744
|
}
|
|
7036
7745
|
const reviewNote = args.metadataEvent.reviewRecommended === true ? " 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.";
|
|
7037
7746
|
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path;${reviewNote}`;
|
|
@@ -7070,7 +7779,7 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
|
|
|
7070
7779
|
}
|
|
7071
7780
|
return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
|
|
7072
7781
|
}
|
|
7073
|
-
if (args.event === "monitor:
|
|
7782
|
+
if (args.event === "monitor:no_progress") {
|
|
7074
7783
|
return `[System] ${args.nodeLabel} is still reported as generating after a long interval${metadata}. Wait for pendingCoordinatorEvents or a completion/status event; if the user explicitly asks for status, make one bounded status check and then wait again.`;
|
|
7075
7784
|
}
|
|
7076
7785
|
if (args.event === "worktree_bootstrap_complete") {
|
|
@@ -7209,9 +7918,9 @@ function getPendingEventsPath(meshId, coordinatorDaemonId) {
|
|
|
7209
7918
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7210
7919
|
if (coordinatorDaemonId) {
|
|
7211
7920
|
const safeDaemon = coordinatorDaemonId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7212
|
-
return (0,
|
|
7921
|
+
return (0, import_path9.join)(getLedgerDir(), `${safe}-${safeDaemon}.pending-events.jsonl`);
|
|
7213
7922
|
}
|
|
7214
|
-
return (0,
|
|
7923
|
+
return (0, import_path9.join)(getLedgerDir(), `${safe}.pending-events.jsonl`);
|
|
7215
7924
|
}
|
|
7216
7925
|
function readPendingMeshCoordinatorEventsFromDisk(meshId, coordinatorDaemonId) {
|
|
7217
7926
|
if (!meshId) return [];
|
|
@@ -7220,9 +7929,9 @@ function readPendingMeshCoordinatorEventsFromDisk(meshId, coordinatorDaemonId) {
|
|
|
7220
7929
|
const paths = primaryDaemonId ? [getPendingEventsPath(meshId, primaryDaemonId), getPendingEventsPath(meshId)] : [getPendingEventsPath(meshId)];
|
|
7221
7930
|
const events = [];
|
|
7222
7931
|
for (const path42 of paths) {
|
|
7223
|
-
if (!(0,
|
|
7932
|
+
if (!(0, import_fs9.existsSync)(path42)) continue;
|
|
7224
7933
|
try {
|
|
7225
|
-
const raw = (0,
|
|
7934
|
+
const raw = (0, import_fs9.readFileSync)(path42, "utf-8");
|
|
7226
7935
|
const parsed = raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
7227
7936
|
try {
|
|
7228
7937
|
return [JSON.parse(line)];
|
|
@@ -7297,11 +8006,11 @@ function reconcilePendingMeshCoordinatorEvents(meshId, events) {
|
|
|
7297
8006
|
}
|
|
7298
8007
|
function trimPendingEventsIfNeeded(path42) {
|
|
7299
8008
|
try {
|
|
7300
|
-
if (!(0,
|
|
7301
|
-
if ((0,
|
|
7302
|
-
const lines = (0,
|
|
8009
|
+
if (!(0, import_fs9.existsSync)(path42)) return;
|
|
8010
|
+
if ((0, import_fs9.statSync)(path42).size <= MAX_PENDING_EVENTS_BYTES) return;
|
|
8011
|
+
const lines = (0, import_fs9.readFileSync)(path42, "utf-8").split("\n").filter(Boolean);
|
|
7303
8012
|
if (lines.length <= MAX_PENDING_EVENTS_KEEP) return;
|
|
7304
|
-
(0,
|
|
8013
|
+
(0, import_fs9.writeFileSync)(path42, lines.slice(-MAX_PENDING_EVENTS_KEEP).join("\n") + "\n", "utf-8");
|
|
7305
8014
|
} catch {
|
|
7306
8015
|
}
|
|
7307
8016
|
}
|
|
@@ -7330,7 +8039,7 @@ function queuePendingMeshCoordinatorEvent(event) {
|
|
|
7330
8039
|
}
|
|
7331
8040
|
const path42 = getPendingEventsPath(event.meshId, event.targetCoordinatorDaemonId);
|
|
7332
8041
|
trimPendingEventsIfNeeded(path42);
|
|
7333
|
-
(0,
|
|
8042
|
+
(0, import_fs9.appendFileSync)(path42, JSON.stringify(event) + "\n", "utf-8");
|
|
7334
8043
|
return true;
|
|
7335
8044
|
} catch (e) {
|
|
7336
8045
|
LOG.warn("MeshEvents", `Failed to persist pending coordinator event: ${e?.message || e}`);
|
|
@@ -7340,20 +8049,20 @@ function queuePendingMeshCoordinatorEvent(event) {
|
|
|
7340
8049
|
function atomicDrainFile(path42) {
|
|
7341
8050
|
const tmpPath = `${path42}.draining`;
|
|
7342
8051
|
try {
|
|
7343
|
-
(0,
|
|
8052
|
+
(0, import_fs9.renameSync)(path42, tmpPath);
|
|
7344
8053
|
} catch {
|
|
7345
8054
|
return null;
|
|
7346
8055
|
}
|
|
7347
8056
|
try {
|
|
7348
|
-
const content = (0,
|
|
8057
|
+
const content = (0, import_fs9.readFileSync)(tmpPath, "utf-8");
|
|
7349
8058
|
try {
|
|
7350
|
-
(0,
|
|
8059
|
+
(0, import_fs9.unlinkSync)(tmpPath);
|
|
7351
8060
|
} catch {
|
|
7352
8061
|
}
|
|
7353
8062
|
return content;
|
|
7354
8063
|
} catch {
|
|
7355
8064
|
try {
|
|
7356
|
-
(0,
|
|
8065
|
+
(0, import_fs9.unlinkSync)(tmpPath);
|
|
7357
8066
|
} catch {
|
|
7358
8067
|
}
|
|
7359
8068
|
return null;
|
|
@@ -7362,16 +8071,16 @@ function atomicDrainFile(path42) {
|
|
|
7362
8071
|
function selectiveDrainFile(path42, predicate) {
|
|
7363
8072
|
const tmpPath = `${path42}.draining`;
|
|
7364
8073
|
try {
|
|
7365
|
-
(0,
|
|
8074
|
+
(0, import_fs9.renameSync)(path42, tmpPath);
|
|
7366
8075
|
} catch {
|
|
7367
8076
|
return [];
|
|
7368
8077
|
}
|
|
7369
8078
|
let content;
|
|
7370
8079
|
try {
|
|
7371
|
-
content = (0,
|
|
8080
|
+
content = (0, import_fs9.readFileSync)(tmpPath, "utf-8");
|
|
7372
8081
|
} catch {
|
|
7373
8082
|
try {
|
|
7374
|
-
(0,
|
|
8083
|
+
(0, import_fs9.unlinkSync)(tmpPath);
|
|
7375
8084
|
} catch {
|
|
7376
8085
|
}
|
|
7377
8086
|
return [];
|
|
@@ -7394,12 +8103,12 @@ function selectiveDrainFile(path42, predicate) {
|
|
|
7394
8103
|
}
|
|
7395
8104
|
try {
|
|
7396
8105
|
if (keptLines.length > 0) {
|
|
7397
|
-
(0,
|
|
8106
|
+
(0, import_fs9.writeFileSync)(path42, keptLines.join("\n") + "\n", "utf-8");
|
|
7398
8107
|
}
|
|
7399
|
-
(0,
|
|
8108
|
+
(0, import_fs9.unlinkSync)(tmpPath);
|
|
7400
8109
|
} catch {
|
|
7401
8110
|
try {
|
|
7402
|
-
if ((0,
|
|
8111
|
+
if ((0, import_fs9.existsSync)(tmpPath) && !(0, import_fs9.existsSync)(path42)) (0, import_fs9.renameSync)(tmpPath, path42);
|
|
7403
8112
|
} catch {
|
|
7404
8113
|
}
|
|
7405
8114
|
return [];
|
|
@@ -7493,18 +8202,18 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
|
7493
8202
|
}
|
|
7494
8203
|
const paths = coordinatorDaemonId ? [getPendingEventsPath(meshId, coordinatorDaemonId), getPendingEventsPath(meshId)] : [getPendingEventsPath(meshId)];
|
|
7495
8204
|
for (const path42 of paths) {
|
|
7496
|
-
if ((0,
|
|
7497
|
-
(0,
|
|
8205
|
+
if ((0, import_fs9.existsSync)(path42)) try {
|
|
8206
|
+
(0, import_fs9.unlinkSync)(path42);
|
|
7498
8207
|
} catch {
|
|
7499
8208
|
}
|
|
7500
8209
|
}
|
|
7501
8210
|
}
|
|
7502
|
-
var
|
|
8211
|
+
var import_fs9, import_path9, import_crypto7, REFINE_TERMINAL_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
|
|
7503
8212
|
var init_mesh_events_pending = __esm({
|
|
7504
8213
|
"src/mesh/mesh-events-pending.ts"() {
|
|
7505
8214
|
"use strict";
|
|
7506
|
-
|
|
7507
|
-
|
|
8215
|
+
import_fs9 = require("fs");
|
|
8216
|
+
import_path9 = require("path");
|
|
7508
8217
|
import_crypto7 = require("crypto");
|
|
7509
8218
|
init_logger();
|
|
7510
8219
|
init_mesh_ledger();
|
|
@@ -7860,7 +8569,7 @@ function reconcileDirectDispatchCompletionFromTranscript(args) {
|
|
|
7860
8569
|
});
|
|
7861
8570
|
return { reconciled: true, kind, workerResult, ledgerEntryId: entry.id };
|
|
7862
8571
|
}
|
|
7863
|
-
function
|
|
8572
|
+
function buildNoProgressCompletionReconciliation(args) {
|
|
7864
8573
|
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
7865
8574
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
7866
8575
|
const providerType = readNonEmptyString2(args.metadataEvent.providerType);
|
|
@@ -7879,8 +8588,8 @@ function buildLongGeneratingCompletionReconciliation(args) {
|
|
|
7879
8588
|
providerType,
|
|
7880
8589
|
providerSessionId,
|
|
7881
8590
|
finalSummary,
|
|
7882
|
-
source: "
|
|
7883
|
-
reconciledFromEvent: "monitor:
|
|
8591
|
+
source: "no_progress_reconciliation",
|
|
8592
|
+
reconciledFromEvent: "monitor:no_progress",
|
|
7884
8593
|
timestamp: args.metadataEvent.timestamp ?? Date.now(),
|
|
7885
8594
|
completionDiagnostic: {
|
|
7886
8595
|
...completionDiagnostic || {},
|
|
@@ -7896,7 +8605,7 @@ function buildLongGeneratingCompletionReconciliation(args) {
|
|
|
7896
8605
|
if (!terminal) return null;
|
|
7897
8606
|
return {
|
|
7898
8607
|
...args.metadataEvent,
|
|
7899
|
-
source: "
|
|
8608
|
+
source: "no_progress_terminal_ledger_suppression",
|
|
7900
8609
|
terminalLedgerKind: terminal.kind,
|
|
7901
8610
|
terminalLedgerAt: terminal.timestamp
|
|
7902
8611
|
};
|
|
@@ -8336,7 +9045,7 @@ function resolveCommandPath(command) {
|
|
|
8336
9045
|
if (isExplicitCommandPath(trimmed)) {
|
|
8337
9046
|
const expanded = expandHome(trimmed);
|
|
8338
9047
|
const candidate = path11.isAbsolute(expanded) ? expanded : path11.resolve(expanded);
|
|
8339
|
-
return (0,
|
|
9048
|
+
return (0, import_fs10.existsSync)(candidate) ? candidate : null;
|
|
8340
9049
|
}
|
|
8341
9050
|
return null;
|
|
8342
9051
|
}
|
|
@@ -8346,7 +9055,7 @@ async function resolveDetectionPath(command, whichCmd) {
|
|
|
8346
9055
|
const whichResult = await execAsync(`${whichCmd} ${shellQuote(command)}`);
|
|
8347
9056
|
if (whichResult) return whichResult.split("\n")[0];
|
|
8348
9057
|
const resolved = findBinary(command);
|
|
8349
|
-
if (path11.isAbsolute(resolved) && (0,
|
|
9058
|
+
if (path11.isAbsolute(resolved) && (0, import_fs10.existsSync)(resolved)) return resolved;
|
|
8350
9059
|
return null;
|
|
8351
9060
|
}
|
|
8352
9061
|
function execAsync(cmd, timeoutMs = 5e3) {
|
|
@@ -8441,14 +9150,14 @@ async function detectCLI(cliId, providerLoader, options) {
|
|
|
8441
9150
|
const all = await detectCLIs(providerLoader, options);
|
|
8442
9151
|
return all.find((c) => c.id === resolvedId && c.installed) || null;
|
|
8443
9152
|
}
|
|
8444
|
-
var import_child_process, os6, path11,
|
|
9153
|
+
var import_child_process, os6, path11, import_fs10;
|
|
8445
9154
|
var init_cli_detector = __esm({
|
|
8446
9155
|
"src/detection/cli-detector.ts"() {
|
|
8447
9156
|
"use strict";
|
|
8448
9157
|
import_child_process = require("child_process");
|
|
8449
9158
|
os6 = __toESM(require("os"));
|
|
8450
9159
|
path11 = __toESM(require("path"));
|
|
8451
|
-
|
|
9160
|
+
import_fs10 = require("fs");
|
|
8452
9161
|
init_provider_cli_shared();
|
|
8453
9162
|
}
|
|
8454
9163
|
});
|
|
@@ -8747,7 +9456,7 @@ function hasRecentIntentionalCleanupStop(meshId, sessionId, nodeId) {
|
|
|
8747
9456
|
return false;
|
|
8748
9457
|
}
|
|
8749
9458
|
function shouldSuppressIntentionalCleanupStop(args) {
|
|
8750
|
-
if (args.event !== "agent:stopped" && args.event !== "monitor:
|
|
9459
|
+
if (args.event !== "agent:stopped" && args.event !== "monitor:no_progress") return false;
|
|
8751
9460
|
if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
|
|
8752
9461
|
return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
|
|
8753
9462
|
}
|
|
@@ -8963,7 +9672,7 @@ function resolveAutoFastForwardPolicy(mesh) {
|
|
|
8963
9672
|
function sessionStateLooksActive(state) {
|
|
8964
9673
|
const status = readNonEmptyString2(state?.status).toLowerCase();
|
|
8965
9674
|
const chatStatus = readNonEmptyString2(state?.activeChat?.status).toLowerCase();
|
|
8966
|
-
const active = /* @__PURE__ */ new Set(["generating", "streaming", "long_generating", "working", "starting", "waiting_approval"]);
|
|
9675
|
+
const active = /* @__PURE__ */ new Set(["generating", "streaming", "no_progress", "long_generating", "working", "starting", "waiting_approval"]);
|
|
8967
9676
|
return active.has(status) || active.has(chatStatus);
|
|
8968
9677
|
}
|
|
8969
9678
|
function nodeHasActiveMeshWork(components, meshId, nodeId, currentSessionId) {
|
|
@@ -9483,7 +10192,7 @@ async function maybeAutoFastForwardIdleNode(components, args) {
|
|
|
9483
10192
|
const node = mesh?.nodes?.find((candidate) => meshNodeIdMatches(candidate, args.nodeId));
|
|
9484
10193
|
const workspace = readNonEmptyString2(node?.workspace);
|
|
9485
10194
|
if (!workspace) return;
|
|
9486
|
-
if (!(0,
|
|
10195
|
+
if (!(0, import_fs11.existsSync)(workspace)) return;
|
|
9487
10196
|
const policy = resolveAutoFastForwardPolicy(mesh);
|
|
9488
10197
|
if (!policy.enabled) return;
|
|
9489
10198
|
if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId, args.sessionId)) return;
|
|
@@ -9577,24 +10286,24 @@ function injectMeshSystemMessage(components, args) {
|
|
|
9577
10286
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
9578
10287
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
9579
10288
|
}
|
|
9580
|
-
if (args.event === "monitor:
|
|
9581
|
-
const reconciledCompletion =
|
|
10289
|
+
if (args.event === "monitor:no_progress") {
|
|
10290
|
+
const reconciledCompletion = buildNoProgressCompletionReconciliation({
|
|
9582
10291
|
meshId: args.meshId,
|
|
9583
10292
|
nodeId: args.nodeId,
|
|
9584
10293
|
nodeLabel: args.nodeLabel,
|
|
9585
10294
|
metadataEvent: args.metadataEvent,
|
|
9586
10295
|
sourceInstanceId: args.sourceInstanceId
|
|
9587
10296
|
});
|
|
9588
|
-
if (reconciledCompletion?.source === "
|
|
9589
|
-
LOG.info("MeshEvents", `Reconciled
|
|
10297
|
+
if (reconciledCompletion?.source === "no_progress_reconciliation") {
|
|
10298
|
+
LOG.info("MeshEvents", `Reconciled no-progress monitor to completion for session ${eventSessionId || "(unknown session)"}`);
|
|
9590
10299
|
return injectMeshSystemMessage(components, {
|
|
9591
10300
|
...args,
|
|
9592
10301
|
event: "agent:generating_completed",
|
|
9593
10302
|
metadataEvent: reconciledCompletion
|
|
9594
10303
|
});
|
|
9595
10304
|
}
|
|
9596
|
-
if (reconciledCompletion?.source === "
|
|
9597
|
-
LOG.info("MeshEvents", `Suppressed
|
|
10305
|
+
if (reconciledCompletion?.source === "no_progress_terminal_ledger_suppression") {
|
|
10306
|
+
LOG.info("MeshEvents", `Suppressed no-progress monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
|
|
9598
10307
|
return {
|
|
9599
10308
|
success: true,
|
|
9600
10309
|
forwarded: 0,
|
|
@@ -9636,7 +10345,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
9636
10345
|
const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
|
|
9637
10346
|
const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
|
|
9638
10347
|
const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
9639
|
-
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "
|
|
10348
|
+
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "no_progress_reconciliation") {
|
|
9640
10349
|
LOG.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
9641
10350
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
9642
10351
|
}
|
|
@@ -10075,11 +10784,11 @@ function setupMeshEventForwarding(components) {
|
|
|
10075
10784
|
});
|
|
10076
10785
|
});
|
|
10077
10786
|
}
|
|
10078
|
-
var
|
|
10787
|
+
var import_fs11, REMOTE_IDLE_SESSION_TTL_MS, meshByWorkspaceCache, MESH_WORKSPACE_CACHE_TTL_MS, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, MESH_FORCE_INJECT_EVENTS;
|
|
10079
10788
|
var init_mesh_events_coordinator = __esm({
|
|
10080
10789
|
"src/mesh/mesh-events-coordinator.ts"() {
|
|
10081
10790
|
"use strict";
|
|
10082
|
-
|
|
10791
|
+
import_fs11 = require("fs");
|
|
10083
10792
|
init_config();
|
|
10084
10793
|
init_mesh_config();
|
|
10085
10794
|
init_cli_detector();
|
|
@@ -10115,7 +10824,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
10115
10824
|
"agent:waiting_approval",
|
|
10116
10825
|
"agent:stopped",
|
|
10117
10826
|
"agent:ready",
|
|
10118
|
-
"monitor:
|
|
10827
|
+
"monitor:no_progress",
|
|
10119
10828
|
"refine:accepted",
|
|
10120
10829
|
"refine:completed",
|
|
10121
10830
|
"refine:failed",
|
|
@@ -10126,7 +10835,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
10126
10835
|
"agent:generating_completed": "task_completed",
|
|
10127
10836
|
"agent:waiting_approval": "task_approval_needed",
|
|
10128
10837
|
"agent:stopped": "task_failed",
|
|
10129
|
-
"monitor:
|
|
10838
|
+
"monitor:no_progress": "task_stalled"
|
|
10130
10839
|
};
|
|
10131
10840
|
MESH_FORCE_INJECT_EVENTS = /* @__PURE__ */ new Set([
|
|
10132
10841
|
"agent:generating_completed",
|
|
@@ -10779,6 +11488,14 @@ var init_chat_message_normalization = __esm({
|
|
|
10779
11488
|
});
|
|
10780
11489
|
|
|
10781
11490
|
// src/mesh/mesh-reconcile-loop.ts
|
|
11491
|
+
function resolveAutoPruneMinAgeMs() {
|
|
11492
|
+
const raw = readNonEmptyString2(process.env.MESH_AUTO_PRUNE_MIN_AGE_MS);
|
|
11493
|
+
if (raw) {
|
|
11494
|
+
const parsed = Number.parseInt(raw, 10);
|
|
11495
|
+
if (Number.isFinite(parsed) && parsed >= 60 * 6e4 && parsed <= 30 * 24 * 60 * 6e4) return parsed;
|
|
11496
|
+
}
|
|
11497
|
+
return DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
11498
|
+
}
|
|
10782
11499
|
function resolveReconcileIntervalMs() {
|
|
10783
11500
|
const raw = readNonEmptyString2(process.env.MESH_RECONCILE_INTERVAL_MS);
|
|
10784
11501
|
if (raw) {
|
|
@@ -10890,6 +11607,18 @@ async function runMeshReconcileTick(components) {
|
|
|
10890
11607
|
LOG.warn("MeshReconcile", `Completion reconcile failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
10891
11608
|
}
|
|
10892
11609
|
}
|
|
11610
|
+
{
|
|
11611
|
+
const minAgeMs = resolveAutoPruneMinAgeMs();
|
|
11612
|
+
for (const mesh of listMeshes()) {
|
|
11613
|
+
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
11614
|
+
if (!daemonHostsMesh(mesh, selfIds)) continue;
|
|
11615
|
+
try {
|
|
11616
|
+
await autoPruneStaleDirectDispatches(components, mesh, selfIds, localDaemonId, minAgeMs);
|
|
11617
|
+
} catch (e) {
|
|
11618
|
+
LOG.warn("MeshReconcile", `Auto-prune stale direct failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
11619
|
+
}
|
|
11620
|
+
}
|
|
11621
|
+
}
|
|
10893
11622
|
const coordinators = findLiveCoordinators(components);
|
|
10894
11623
|
if (coordinators.length === 0) {
|
|
10895
11624
|
return;
|
|
@@ -11072,6 +11801,68 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
11072
11801
|
}
|
|
11073
11802
|
}
|
|
11074
11803
|
}
|
|
11804
|
+
async function autoPruneStaleDirectDispatches(components, mesh, selfIds, localDaemonId, minAgeMs) {
|
|
11805
|
+
const directDispatches = getActiveDirectDispatches(mesh.id);
|
|
11806
|
+
if (directDispatches.length === 0) return;
|
|
11807
|
+
const liveNodes = await collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId);
|
|
11808
|
+
const result = pruneStaleDirectDispatches({
|
|
11809
|
+
meshId: mesh.id,
|
|
11810
|
+
queue: getQueue(mesh.id),
|
|
11811
|
+
ledgerEntries: readLedgerEntries(mesh.id, { tail: 500 }),
|
|
11812
|
+
directDispatches,
|
|
11813
|
+
nodes: liveNodes,
|
|
11814
|
+
execute: true,
|
|
11815
|
+
minAgeMs,
|
|
11816
|
+
source: "daemon_reconcile_auto_prune"
|
|
11817
|
+
});
|
|
11818
|
+
if (result.prunedCount > 0) {
|
|
11819
|
+
LOG.info("MeshReconcile", `Auto-pruned ${result.prunedCount} orphaned direct dispatch record(s) for mesh ${mesh.id}`);
|
|
11820
|
+
}
|
|
11821
|
+
}
|
|
11822
|
+
async function collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId) {
|
|
11823
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
11824
|
+
return Promise.all(mesh.nodes.map(async (node) => {
|
|
11825
|
+
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
11826
|
+
const isLocalNode = !nodeDaemonId || selfIds.includes(nodeDaemonId) || localDaemonId !== void 0 && nodeDaemonId === localDaemonId;
|
|
11827
|
+
let statusResult;
|
|
11828
|
+
try {
|
|
11829
|
+
if (isLocalNode) {
|
|
11830
|
+
statusResult = await components.commandHandler.handle("get_status_metadata", {});
|
|
11831
|
+
} else if (dispatchMeshCommand) {
|
|
11832
|
+
statusResult = await dispatchMeshCommand(nodeDaemonId, "get_status_metadata", {});
|
|
11833
|
+
} else {
|
|
11834
|
+
return node;
|
|
11835
|
+
}
|
|
11836
|
+
} catch {
|
|
11837
|
+
return node;
|
|
11838
|
+
}
|
|
11839
|
+
const sessions = extractStatusMetadataSessions(statusResult);
|
|
11840
|
+
return sessions.length > 0 ? { ...node, sessions } : node;
|
|
11841
|
+
}));
|
|
11842
|
+
}
|
|
11843
|
+
function extractStatusMetadataSessions(raw) {
|
|
11844
|
+
let cursor = raw;
|
|
11845
|
+
for (let depth = 0; depth < 4 && cursor && typeof cursor === "object"; depth++) {
|
|
11846
|
+
const record = cursor;
|
|
11847
|
+
const status = record.status && typeof record.status === "object" ? record.status : void 0;
|
|
11848
|
+
if (status && Array.isArray(status.sessions)) return status.sessions;
|
|
11849
|
+
if (Array.isArray(record.sessions)) return record.sessions;
|
|
11850
|
+
if (record.payload && typeof record.payload === "object") {
|
|
11851
|
+
cursor = record.payload;
|
|
11852
|
+
continue;
|
|
11853
|
+
}
|
|
11854
|
+
if (record.result && typeof record.result === "object") {
|
|
11855
|
+
cursor = record.result;
|
|
11856
|
+
continue;
|
|
11857
|
+
}
|
|
11858
|
+
if (record.data && typeof record.data === "object") {
|
|
11859
|
+
cursor = record.data;
|
|
11860
|
+
continue;
|
|
11861
|
+
}
|
|
11862
|
+
break;
|
|
11863
|
+
}
|
|
11864
|
+
return [];
|
|
11865
|
+
}
|
|
11075
11866
|
function extractPendingEvents(raw) {
|
|
11076
11867
|
if (Array.isArray(raw)) return raw;
|
|
11077
11868
|
if (raw && typeof raw === "object") {
|
|
@@ -11109,7 +11900,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
11109
11900
|
}
|
|
11110
11901
|
};
|
|
11111
11902
|
}
|
|
11112
|
-
var DEFAULT_RECONCILE_INTERVAL_MS;
|
|
11903
|
+
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
11113
11904
|
var init_mesh_reconcile_loop = __esm({
|
|
11114
11905
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
11115
11906
|
"use strict";
|
|
@@ -11122,9 +11913,12 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
11122
11913
|
init_mesh_unresolved_forward_outbox();
|
|
11123
11914
|
init_mesh_events_utils();
|
|
11124
11915
|
init_mesh_work_queue();
|
|
11916
|
+
init_mesh_ledger();
|
|
11917
|
+
init_mesh_active_work();
|
|
11125
11918
|
init_mesh_events_stale();
|
|
11126
11919
|
init_chat_message_normalization();
|
|
11127
11920
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
11921
|
+
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
11128
11922
|
}
|
|
11129
11923
|
});
|
|
11130
11924
|
|
|
@@ -12189,7 +12983,7 @@ function resolveWin32GlobalBin(trimmed) {
|
|
|
12189
12983
|
if (!dir) continue;
|
|
12190
12984
|
for (const ext of WIN_EXEC_EXT) {
|
|
12191
12985
|
const full = path18.join(dir, trimmed + ext);
|
|
12192
|
-
if ((0,
|
|
12986
|
+
if ((0, import_fs14.existsSync)(full)) return full;
|
|
12193
12987
|
}
|
|
12194
12988
|
}
|
|
12195
12989
|
return null;
|
|
@@ -12198,7 +12992,7 @@ function resolveWin32Executable(command) {
|
|
|
12198
12992
|
if (process.platform !== "win32") return command;
|
|
12199
12993
|
const trimmed = (command || "").trim();
|
|
12200
12994
|
if (!trimmed) return command;
|
|
12201
|
-
if (path18.isAbsolute(trimmed) && (0,
|
|
12995
|
+
if (path18.isAbsolute(trimmed) && (0, import_fs14.existsSync)(trimmed)) return trimmed;
|
|
12202
12996
|
try {
|
|
12203
12997
|
const out = (0, import_child_process4.execFileSync)("where", [trimmed], {
|
|
12204
12998
|
encoding: "utf8",
|
|
@@ -12215,12 +13009,12 @@ function resolveWin32Executable(command) {
|
|
|
12215
13009
|
if (globalBin) return globalBin;
|
|
12216
13010
|
return command;
|
|
12217
13011
|
}
|
|
12218
|
-
var import_child_process4,
|
|
13012
|
+
var import_child_process4, import_fs14, path18, DIRECT_EXEC_EXT, WIN_EXEC_EXT;
|
|
12219
13013
|
var init_resolve_executable = __esm({
|
|
12220
13014
|
"src/cli-adapters/resolve-executable.ts"() {
|
|
12221
13015
|
"use strict";
|
|
12222
13016
|
import_child_process4 = require("child_process");
|
|
12223
|
-
|
|
13017
|
+
import_fs14 = require("fs");
|
|
12224
13018
|
path18 = __toESM(require("path"));
|
|
12225
13019
|
DIRECT_EXEC_EXT = /* @__PURE__ */ new Set([".exe", ".com"]);
|
|
12226
13020
|
WIN_EXEC_EXT = [".exe", ".com", ".cmd", ".bat"];
|
|
@@ -15188,7 +15982,7 @@ ${lastSnapshot}`;
|
|
|
15188
15982
|
};
|
|
15189
15983
|
if (parsedSessionStatus === "idle" && hasFinalAssistant(parsedStatusBeforeSend)) return null;
|
|
15190
15984
|
if (this.engine.currentStatus === "generating") return "current_status_generating";
|
|
15191
|
-
if (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating") {
|
|
15985
|
+
if (parsedSessionStatus === "generating" || parsedSessionStatus === "no_progress" || parsedSessionStatus === "long_generating") {
|
|
15192
15986
|
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
15193
15987
|
const parsedHasActionableModal = Boolean(
|
|
15194
15988
|
parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
|
|
@@ -15265,7 +16059,7 @@ ${lastSnapshot}`;
|
|
|
15265
16059
|
}
|
|
15266
16060
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.engine.currentStatus})`);
|
|
15267
16061
|
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
|
|
15268
|
-
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
|
|
16062
|
+
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "no_progress" || parsedSessionStatus === "long_generating")) {
|
|
15269
16063
|
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
15270
16064
|
const parsedHasActionableModal = Boolean(
|
|
15271
16065
|
parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
|
|
@@ -16775,6 +17569,8 @@ __export(index_exports, {
|
|
|
16775
17569
|
AcpProviderInstance: () => AcpProviderInstance,
|
|
16776
17570
|
AgentStreamPoller: () => AgentStreamPoller,
|
|
16777
17571
|
BUILTIN_CHAT_MESSAGE_KINDS: () => BUILTIN_CHAT_MESSAGE_KINDS,
|
|
17572
|
+
CHANGE_IMPACT_CONFIG_LOCATIONS: () => CHANGE_IMPACT_CONFIG_LOCATIONS,
|
|
17573
|
+
CHANGE_IMPACT_CONFIG_SCHEMA: () => CHANGE_IMPACT_CONFIG_SCHEMA,
|
|
16778
17574
|
CHAT_MESSAGE_ACTIVITY_SOURCES: () => CHAT_MESSAGE_ACTIVITY_SOURCES,
|
|
16779
17575
|
CHAT_MESSAGE_AUDIENCES: () => CHAT_MESSAGE_AUDIENCES,
|
|
16780
17576
|
CHAT_MESSAGE_INTERNAL_SOURCES: () => CHAT_MESSAGE_INTERNAL_SOURCES,
|
|
@@ -16965,6 +17761,7 @@ __export(index_exports, {
|
|
|
16965
17761
|
getSessionHostSurfaceKind: () => getSessionHostSurfaceKind,
|
|
16966
17762
|
getSessionRecoveryContext: () => getSessionRecoveryContext,
|
|
16967
17763
|
getWorkspaceState: () => getWorkspaceState,
|
|
17764
|
+
globToRegExp: () => globToRegExp,
|
|
16968
17765
|
handleGitCommand: () => handleGitCommand,
|
|
16969
17766
|
hasCdpManager: () => hasCdpManager,
|
|
16970
17767
|
hasPendingDependents: () => hasPendingDependents,
|
|
@@ -16998,6 +17795,7 @@ __export(index_exports, {
|
|
|
16998
17795
|
listMeshMissionSummaries: () => listMeshMissionSummaries,
|
|
16999
17796
|
listMeshes: () => listMeshes,
|
|
17000
17797
|
listWorktrees: () => listWorktrees,
|
|
17798
|
+
loadChangeImpactConfig: () => loadChangeImpactConfig,
|
|
17001
17799
|
loadConfig: () => loadConfig,
|
|
17002
17800
|
loadMeshCoordinatorRegistry: () => loadMeshCoordinatorRegistry,
|
|
17003
17801
|
loadMeshRefineConfig: () => loadMeshRefineConfig,
|
|
@@ -17038,6 +17836,7 @@ __export(index_exports, {
|
|
|
17038
17836
|
prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
|
|
17039
17837
|
prepareSessionModalUpdate: () => prepareSessionModalUpdate,
|
|
17040
17838
|
probeCdpPort: () => probeCdpPort,
|
|
17839
|
+
pruneStaleDirectDispatches: () => pruneStaleDirectDispatches,
|
|
17041
17840
|
queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
|
|
17042
17841
|
readAntigravityCliSession: () => readSession3,
|
|
17043
17842
|
readCachedInlineMeshActiveSessionDetails: () => readCachedInlineMeshActiveSessionDetails,
|
|
@@ -17091,6 +17890,7 @@ __export(index_exports, {
|
|
|
17091
17890
|
spawnDetachedDaemonUpgradeHelper: () => spawnDetachedDaemonUpgradeHelper,
|
|
17092
17891
|
startDaemonDevSupport: () => startDaemonDevSupport,
|
|
17093
17892
|
startLocalIpcServer: () => startLocalIpcServer,
|
|
17893
|
+
suggestChangeImpactConfig: () => suggestChangeImpactConfig,
|
|
17094
17894
|
suggestMeshRefineConfig: () => suggestMeshRefineConfig,
|
|
17095
17895
|
summarizeGitStatus: () => summarizeGitStatus,
|
|
17096
17896
|
summarizeMeshAsyncRefineJobs: () => summarizeMeshAsyncRefineJobs,
|
|
@@ -17107,6 +17907,7 @@ __export(index_exports, {
|
|
|
17107
17907
|
updateTaskStatus: () => updateTaskStatus,
|
|
17108
17908
|
upsertMeshMission: () => upsertMeshMission,
|
|
17109
17909
|
upsertSavedProviderSession: () => upsertSavedProviderSession,
|
|
17910
|
+
validateChangeImpactConfig: () => validateChangeImpactConfig,
|
|
17110
17911
|
validateCliProviderManifest: () => validateCliProviderManifest,
|
|
17111
17912
|
validateFsmSpec: () => validateFsmSpec,
|
|
17112
17913
|
validateMeshRefineConfig: () => validateMeshRefineConfig,
|
|
@@ -17476,6 +18277,7 @@ init_repo_mesh_types();
|
|
|
17476
18277
|
// src/git/index.ts
|
|
17477
18278
|
init_git_executor();
|
|
17478
18279
|
init_git_status();
|
|
18280
|
+
init_change_impact_config();
|
|
17479
18281
|
init_git_diff();
|
|
17480
18282
|
|
|
17481
18283
|
// src/git/git-summary.ts
|
|
@@ -18769,18 +19571,18 @@ init_mesh_task_stats();
|
|
|
18769
19571
|
init_mesh_review_inbox();
|
|
18770
19572
|
|
|
18771
19573
|
// src/mesh/coordinator-registry.ts
|
|
18772
|
-
var
|
|
18773
|
-
var
|
|
19574
|
+
var import_path6 = require("path");
|
|
19575
|
+
var import_fs6 = require("fs");
|
|
18774
19576
|
init_config();
|
|
18775
19577
|
var _registry = /* @__PURE__ */ new Map();
|
|
18776
19578
|
function getRegistryPath() {
|
|
18777
|
-
return (0,
|
|
19579
|
+
return (0, import_path6.join)(getDaemonDataDir(), "mesh-coordinators.json");
|
|
18778
19580
|
}
|
|
18779
19581
|
function loadMeshCoordinatorRegistry() {
|
|
18780
19582
|
const path42 = getRegistryPath();
|
|
18781
|
-
if (!(0,
|
|
19583
|
+
if (!(0, import_fs6.existsSync)(path42)) return;
|
|
18782
19584
|
try {
|
|
18783
|
-
const raw = JSON.parse((0,
|
|
19585
|
+
const raw = JSON.parse((0, import_fs6.readFileSync)(path42, "utf-8"));
|
|
18784
19586
|
if (!Array.isArray(raw)) return;
|
|
18785
19587
|
_registry.clear();
|
|
18786
19588
|
for (const entry of raw) {
|
|
@@ -18793,7 +19595,7 @@ function loadMeshCoordinatorRegistry() {
|
|
|
18793
19595
|
}
|
|
18794
19596
|
function saveRegistry() {
|
|
18795
19597
|
try {
|
|
18796
|
-
(0,
|
|
19598
|
+
(0, import_fs6.writeFileSync)(
|
|
18797
19599
|
getRegistryPath(),
|
|
18798
19600
|
JSON.stringify([..._registry.values()], null, 2),
|
|
18799
19601
|
{ encoding: "utf-8", mode: 384 }
|
|
@@ -18828,9 +19630,9 @@ function listCoordinatorsForWorkspace(workspace) {
|
|
|
18828
19630
|
}
|
|
18829
19631
|
|
|
18830
19632
|
// src/mesh/refine-config.ts
|
|
18831
|
-
var
|
|
18832
|
-
var
|
|
18833
|
-
var
|
|
19633
|
+
var import_fs7 = require("fs");
|
|
19634
|
+
var import_path7 = require("path");
|
|
19635
|
+
var yaml2 = __toESM(require("js-yaml"));
|
|
18834
19636
|
var MESH_REFINE_VALIDATION_CATEGORIES = ["typecheck", "test", "lint", "build"];
|
|
18835
19637
|
var MESH_REFINE_CONFIG_LOCATIONS = [
|
|
18836
19638
|
".adhdev/refine.json",
|
|
@@ -18971,7 +19773,7 @@ function normalizeMeshCommandConfig(entry, source) {
|
|
|
18971
19773
|
}
|
|
18972
19774
|
};
|
|
18973
19775
|
}
|
|
18974
|
-
var
|
|
19776
|
+
var isRecord2 = isMeshConfigRecord;
|
|
18975
19777
|
function validateMeshRefineConfig(config, source = "inline") {
|
|
18976
19778
|
const errors = [];
|
|
18977
19779
|
const bootstrapCommands = [];
|
|
@@ -18979,14 +19781,14 @@ function validateMeshRefineConfig(config, source = "inline") {
|
|
|
18979
19781
|
const rejectedCommands = [];
|
|
18980
19782
|
const deprecationWarnings = [];
|
|
18981
19783
|
let bootstrapMode = "inherit";
|
|
18982
|
-
if (!
|
|
19784
|
+
if (!isRecord2(config)) return { valid: false, errors: ["config must be an object"], bootstrapCommands, commands, rejectedCommands, bootstrapMode, deprecationWarnings };
|
|
18983
19785
|
if (config.version !== 1) errors.push("version must be 1");
|
|
18984
19786
|
if (config.allowAutoPublishSubmoduleMainCommits !== void 0 && typeof config.allowAutoPublishSubmoduleMainCommits !== "boolean") {
|
|
18985
19787
|
errors.push("allowAutoPublishSubmoduleMainCommits must be a boolean when provided");
|
|
18986
19788
|
}
|
|
18987
19789
|
const validation = config.validation;
|
|
18988
|
-
if (validation !== void 0 && !
|
|
18989
|
-
const rawBootstrapMode =
|
|
19790
|
+
if (validation !== void 0 && !isRecord2(validation)) errors.push("validation must be an object");
|
|
19791
|
+
const rawBootstrapMode = isRecord2(validation) ? validation.bootstrap : void 0;
|
|
18990
19792
|
if (rawBootstrapMode !== void 0) {
|
|
18991
19793
|
if (rawBootstrapMode === "inherit" || rawBootstrapMode === "skip") {
|
|
18992
19794
|
bootstrapMode = rawBootstrapMode;
|
|
@@ -18994,8 +19796,8 @@ function validateMeshRefineConfig(config, source = "inline") {
|
|
|
18994
19796
|
errors.push("validation.bootstrap must be 'inherit' or 'skip' when provided");
|
|
18995
19797
|
}
|
|
18996
19798
|
}
|
|
18997
|
-
const rawCommands =
|
|
18998
|
-
const rawBootstrapCommands =
|
|
19799
|
+
const rawCommands = isRecord2(validation) ? validation.commands : void 0;
|
|
19800
|
+
const rawBootstrapCommands = isRecord2(validation) ? validation.bootstrapCommands : void 0;
|
|
18999
19801
|
if (rawCommands !== void 0 && !Array.isArray(rawCommands)) errors.push("validation.commands must be an array");
|
|
19000
19802
|
if (rawBootstrapCommands !== void 0 && !Array.isArray(rawBootstrapCommands)) errors.push("validation.bootstrapCommands must be an array");
|
|
19001
19803
|
if (Array.isArray(rawBootstrapCommands) && rawBootstrapCommands.length > 0) {
|
|
@@ -19018,9 +19820,9 @@ function validateMeshRefineConfig(config, source = "inline") {
|
|
|
19018
19820
|
if (rejectedCommands.length) errors.push("one or more validation commands are invalid");
|
|
19019
19821
|
return { valid: errors.length === 0, errors, bootstrapCommands, commands, rejectedCommands, bootstrapMode, deprecationWarnings };
|
|
19020
19822
|
}
|
|
19021
|
-
function
|
|
19823
|
+
function parseConfigText2(path42, text) {
|
|
19022
19824
|
if (/\.json$/i.test(path42)) return JSON.parse(text);
|
|
19023
|
-
return
|
|
19825
|
+
return yaml2.load(text);
|
|
19024
19826
|
}
|
|
19025
19827
|
function loadMeshRefineConfig(mesh, workspace) {
|
|
19026
19828
|
const policy = mesh?.policy && typeof mesh.policy === "object" && !Array.isArray(mesh.policy) ? mesh.policy : {};
|
|
@@ -19031,10 +19833,10 @@ function loadMeshRefineConfig(mesh, workspace) {
|
|
|
19031
19833
|
return { config: inline, source: "mesh.policy.refineConfig", sourceType: "mesh_policy" };
|
|
19032
19834
|
}
|
|
19033
19835
|
for (const relative5 of MESH_REFINE_CONFIG_LOCATIONS) {
|
|
19034
|
-
const configPath = (0,
|
|
19035
|
-
if (!(0,
|
|
19836
|
+
const configPath = (0, import_path7.join)(workspace, relative5);
|
|
19837
|
+
if (!(0, import_fs7.existsSync)(configPath)) continue;
|
|
19036
19838
|
try {
|
|
19037
|
-
const parsed =
|
|
19839
|
+
const parsed = parseConfigText2(configPath, (0, import_fs7.readFileSync)(configPath, "utf-8"));
|
|
19038
19840
|
const validation = validateMeshRefineConfig(parsed, relative5);
|
|
19039
19841
|
if (!validation.valid) return { source: relative5, sourceType: "invalid", path: configPath, error: String(validation.rejectedCommands[0]?.reason || validation.errors.join("; ")) };
|
|
19040
19842
|
return { config: parsed, source: relative5, sourceType: "repo_file", path: configPath };
|
|
@@ -19050,20 +19852,20 @@ function loadMeshRefineConfig(mesh, workspace) {
|
|
|
19050
19852
|
}
|
|
19051
19853
|
function readPackageScripts(workspace) {
|
|
19052
19854
|
try {
|
|
19053
|
-
const parsed = JSON.parse((0,
|
|
19054
|
-
return
|
|
19855
|
+
const parsed = JSON.parse((0, import_fs7.readFileSync)((0, import_path7.join)(workspace, "package.json"), "utf-8"));
|
|
19856
|
+
return isRecord2(parsed?.scripts) ? parsed.scripts : {};
|
|
19055
19857
|
} catch {
|
|
19056
19858
|
return {};
|
|
19057
19859
|
}
|
|
19058
19860
|
}
|
|
19059
19861
|
function collectProjectContextSuggestions(mesh) {
|
|
19060
19862
|
const commands = mesh?.projectContext?.commands;
|
|
19061
|
-
if (!
|
|
19863
|
+
if (!isRecord2(commands)) return [];
|
|
19062
19864
|
const suggestions = [];
|
|
19063
19865
|
for (const category of MESH_REFINE_VALIDATION_CATEGORIES) {
|
|
19064
19866
|
const entries = Array.isArray(commands[category]) ? commands[category] : [];
|
|
19065
19867
|
for (const entry of entries) {
|
|
19066
|
-
if (
|
|
19868
|
+
if (isRecord2(entry) && typeof entry.command === "string") suggestions.push({ command: entry.command, category });
|
|
19067
19869
|
}
|
|
19068
19870
|
}
|
|
19069
19871
|
return suggestions;
|
|
@@ -19127,12 +19929,12 @@ function resolveMeshRefineValidationPlan(mesh, workspace) {
|
|
|
19127
19929
|
}
|
|
19128
19930
|
|
|
19129
19931
|
// src/mesh/worktree-bootstrap-config.ts
|
|
19130
|
-
var
|
|
19131
|
-
var
|
|
19932
|
+
var import_fs8 = require("fs");
|
|
19933
|
+
var import_path8 = require("path");
|
|
19132
19934
|
var import_node_child_process3 = require("child_process");
|
|
19133
19935
|
var import_node_crypto2 = require("crypto");
|
|
19134
19936
|
var import_node_util3 = require("util");
|
|
19135
|
-
var
|
|
19937
|
+
var yaml3 = __toESM(require("js-yaml"));
|
|
19136
19938
|
var MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS = [
|
|
19137
19939
|
".adhdev/worktree_bootstrap.json",
|
|
19138
19940
|
".adhdev/worktree_bootstrap.yaml",
|
|
@@ -19177,9 +19979,9 @@ var MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA = {
|
|
|
19177
19979
|
var DEFAULT_TIMEOUT_MS2 = 12e4;
|
|
19178
19980
|
var DEFAULT_OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
19179
19981
|
var OUTPUT_SUMMARY_CHARS = 2e3;
|
|
19180
|
-
function
|
|
19982
|
+
function parseConfigText3(path42, text) {
|
|
19181
19983
|
if (/\.json$/i.test(path42)) return JSON.parse(text);
|
|
19182
|
-
return
|
|
19984
|
+
return yaml3.load(text);
|
|
19183
19985
|
}
|
|
19184
19986
|
function truncateOutput(value) {
|
|
19185
19987
|
const text = typeof value === "string" ? value : value == null ? "" : String(value);
|
|
@@ -19219,10 +20021,10 @@ function loadMeshWorktreeBootstrapConfig(mesh, workspace) {
|
|
|
19219
20021
|
return { config: inline, source: "mesh.policy.worktreeBootstrapConfig", sourceType: "mesh_policy" };
|
|
19220
20022
|
}
|
|
19221
20023
|
for (const relative5 of MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS) {
|
|
19222
|
-
const configPath = (0,
|
|
19223
|
-
if (!(0,
|
|
20024
|
+
const configPath = (0, import_path8.join)(workspace, relative5);
|
|
20025
|
+
if (!(0, import_fs8.existsSync)(configPath)) continue;
|
|
19224
20026
|
try {
|
|
19225
|
-
const parsed =
|
|
20027
|
+
const parsed = parseConfigText3(configPath, (0, import_fs8.readFileSync)(configPath, "utf-8"));
|
|
19226
20028
|
const validation = validateMeshWorktreeBootstrapConfig(parsed, relative5);
|
|
19227
20029
|
if (!validation.valid) return { source: relative5, sourceType: "invalid", path: configPath, error: String(validation.rejectedCommands[0]?.reason || validation.errors.join("; ")) };
|
|
19228
20030
|
return { config: parsed, source: relative5, sourceType: "repo_file", path: configPath };
|
|
@@ -19235,9 +20037,9 @@ function loadMeshWorktreeBootstrapConfig(mesh, workspace) {
|
|
|
19235
20037
|
function computeStaleInputsDigest(workspace, staleInputs) {
|
|
19236
20038
|
const digest = {};
|
|
19237
20039
|
for (const relative5 of staleInputs ?? []) {
|
|
19238
|
-
const filePath = (0,
|
|
20040
|
+
const filePath = (0, import_path8.join)(workspace, relative5);
|
|
19239
20041
|
try {
|
|
19240
|
-
digest[relative5] = (0, import_node_crypto2.createHash)("sha256").update((0,
|
|
20042
|
+
digest[relative5] = (0, import_node_crypto2.createHash)("sha256").update((0, import_fs8.readFileSync)(filePath)).digest("hex");
|
|
19241
20043
|
} catch {
|
|
19242
20044
|
digest[relative5] = "absent";
|
|
19243
20045
|
}
|
|
@@ -19307,10 +20109,10 @@ async function runMeshWorktreeBootstrap(mesh, workspace) {
|
|
|
19307
20109
|
staleInputs: loaded.config.staleInputs
|
|
19308
20110
|
};
|
|
19309
20111
|
const staleInputPaths = loaded.config.staleInputs ?? [];
|
|
19310
|
-
const initiallyAbsent = staleInputPaths.filter((p) => !(0,
|
|
20112
|
+
const initiallyAbsent = staleInputPaths.filter((p) => !(0, import_fs8.existsSync)((0, import_path8.join)(workspace, p)));
|
|
19311
20113
|
for (const command of validation.commands) {
|
|
19312
20114
|
if (initiallyAbsent.length > 0) {
|
|
19313
|
-
const appearedNow = initiallyAbsent.filter((p) => (0,
|
|
20115
|
+
const appearedNow = initiallyAbsent.filter((p) => (0, import_fs8.existsSync)((0, import_path8.join)(workspace, p)));
|
|
19314
20116
|
if (appearedNow.length > 0) {
|
|
19315
20117
|
state.status = "stale";
|
|
19316
20118
|
state.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -19318,7 +20120,7 @@ async function runMeshWorktreeBootstrap(mesh, workspace) {
|
|
|
19318
20120
|
return state;
|
|
19319
20121
|
}
|
|
19320
20122
|
}
|
|
19321
|
-
const cwd = command.cwd ? (0,
|
|
20123
|
+
const cwd = command.cwd ? (0, import_path8.resolve)(workspace, command.cwd) : workspace;
|
|
19322
20124
|
const startedAt = Date.now();
|
|
19323
20125
|
state.lastCommand = command.displayCommand;
|
|
19324
20126
|
try {
|
|
@@ -19440,331 +20242,7 @@ function buildMeshLedgerReconciliationEvidence(meshId, replicas) {
|
|
|
19440
20242
|
|
|
19441
20243
|
// src/index.ts
|
|
19442
20244
|
init_mesh_work_queue();
|
|
19443
|
-
|
|
19444
|
-
// src/mesh/mesh-active-work.ts
|
|
19445
|
-
init_dist();
|
|
19446
|
-
var DIRECT_DISPATCH_VIA = /* @__PURE__ */ new Set(["p2p_direct", "local_direct", "mesh_send_task"]);
|
|
19447
|
-
var TERMINAL_LEDGER_KINDS = /* @__PURE__ */ new Set(["task_completed", "task_failed", "task_stalled"]);
|
|
19448
|
-
function readString6(value) {
|
|
19449
|
-
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
19450
|
-
}
|
|
19451
|
-
function summarizeMessage(message) {
|
|
19452
|
-
const oneLine2 = message.replace(/\s+/g, " ").trim();
|
|
19453
|
-
const title = oneLine2.length > 96 ? `${oneLine2.slice(0, 93)}...` : oneLine2;
|
|
19454
|
-
return { title: title || "(untitled task)", summary: oneLine2 };
|
|
19455
|
-
}
|
|
19456
|
-
function elapsedSince(value, now) {
|
|
19457
|
-
const started = value ? new Date(value).getTime() : Number.NaN;
|
|
19458
|
-
return Number.isFinite(started) ? Math.max(0, now - started) : 0;
|
|
19459
|
-
}
|
|
19460
|
-
function sessionStatusFromNodes(nodes, nodeId, sessionId) {
|
|
19461
|
-
if (!Array.isArray(nodes)) return {};
|
|
19462
|
-
if (!nodeId) return { staleReason: "direct task has no node id" };
|
|
19463
|
-
const node = nodes.find((item) => meshNodeIdMatches(item, nodeId));
|
|
19464
|
-
if (!node) return { staleReason: "direct task node is no longer in the live mesh" };
|
|
19465
|
-
if (!sessionId) return {};
|
|
19466
|
-
const candidates = [];
|
|
19467
|
-
for (const value of [
|
|
19468
|
-
node.sessions,
|
|
19469
|
-
node.activeSessions,
|
|
19470
|
-
node.active_sessions,
|
|
19471
|
-
node.activeSessionDetails,
|
|
19472
|
-
node.active_session_details,
|
|
19473
|
-
node.sessionDetails,
|
|
19474
|
-
node.session_details,
|
|
19475
|
-
node.lastProbe?.sessions,
|
|
19476
|
-
node.last_probe?.sessions,
|
|
19477
|
-
node.lastProbe?.status?.sessions,
|
|
19478
|
-
node.last_probe?.status?.sessions
|
|
19479
|
-
]) {
|
|
19480
|
-
if (Array.isArray(value)) candidates.push(...value);
|
|
19481
|
-
}
|
|
19482
|
-
for (const value of [node.activeSession, node.active_session, node.currentSession, node.current_session, node.runtimeSession, node.runtime_session, node.session]) {
|
|
19483
|
-
if (value && typeof value === "object") candidates.push(value);
|
|
19484
|
-
}
|
|
19485
|
-
const session = candidates.find((item) => {
|
|
19486
|
-
if (typeof item === "string") return item === sessionId;
|
|
19487
|
-
const id = readString6(item?.id) || readString6(item?.sessionId) || readString6(item?.session_id) || readString6(item?.runtimeSessionId) || readString6(item?.instanceId);
|
|
19488
|
-
return id === sessionId;
|
|
19489
|
-
});
|
|
19490
|
-
if (!session) return { staleReason: "direct task session is not present in live session records" };
|
|
19491
|
-
if (typeof session === "string") return {};
|
|
19492
|
-
const raw = `${readString6(session.status) || ""} ${readString6(session.lifecycle) || ""} ${readString6(session.state) || ""} ${readString6(session.activeChat?.status) || ""}`.toLowerCase();
|
|
19493
|
-
if (raw.includes("approval")) return { status: "awaiting_approval" };
|
|
19494
|
-
if (raw.includes("generating") || raw.includes("running") || raw.includes("busy")) return { status: "generating" };
|
|
19495
|
-
if (raw.includes("failed") || raw.includes("stopped") || raw.includes("terminated") || raw.includes("exited")) return { status: "failed" };
|
|
19496
|
-
if (raw.includes("idle") || raw.includes("waiting_input") || raw.includes("ready")) return { status: "idle" };
|
|
19497
|
-
return {};
|
|
19498
|
-
}
|
|
19499
|
-
function isDirectDispatch(entry) {
|
|
19500
|
-
if (entry.kind !== "task_dispatched") return false;
|
|
19501
|
-
const payload = entry.payload || {};
|
|
19502
|
-
if (payload.source === "direct") return true;
|
|
19503
|
-
const via = readString6(payload.via);
|
|
19504
|
-
return Boolean(via && DIRECT_DISPATCH_VIA.has(via) && payload.source !== "queue");
|
|
19505
|
-
}
|
|
19506
|
-
function directDispatchTaskId(entry) {
|
|
19507
|
-
return readString6(entry.payload?.taskId) || entry.id;
|
|
19508
|
-
}
|
|
19509
|
-
function terminalMatchesDispatch(terminal, dispatch, taskId) {
|
|
19510
|
-
const terminalTaskId = readString6(terminal.payload?.taskId);
|
|
19511
|
-
if (terminalTaskId && terminalTaskId === taskId) return true;
|
|
19512
|
-
if (terminalTaskId && terminalTaskId !== taskId) return false;
|
|
19513
|
-
if (dispatch.sessionId && terminal.sessionId === dispatch.sessionId) return true;
|
|
19514
|
-
return Boolean(dispatch.nodeId && terminal.nodeId === dispatch.nodeId && !dispatch.sessionId);
|
|
19515
|
-
}
|
|
19516
|
-
function statusFromTerminal(entry) {
|
|
19517
|
-
if (entry.kind === "task_approval_needed") return "awaiting_approval";
|
|
19518
|
-
if (entry.kind === "task_completed") return "idle";
|
|
19519
|
-
return "failed";
|
|
19520
|
-
}
|
|
19521
|
-
function buildMeshActiveWorkSummary(activeWork) {
|
|
19522
|
-
const statusCounts = {
|
|
19523
|
-
pending: 0,
|
|
19524
|
-
assigned: 0,
|
|
19525
|
-
generating: 0,
|
|
19526
|
-
idle: 0,
|
|
19527
|
-
failed: 0,
|
|
19528
|
-
awaiting_approval: 0
|
|
19529
|
-
};
|
|
19530
|
-
const sourceCounts = { queue: 0, direct: 0 };
|
|
19531
|
-
for (const item of activeWork) {
|
|
19532
|
-
sourceCounts[item.source] += 1;
|
|
19533
|
-
statusCounts[item.status] += 1;
|
|
19534
|
-
}
|
|
19535
|
-
const staleDirectCount = activeWork.filter((item) => item.source === "direct" && item.staleReason).length;
|
|
19536
|
-
const staleDirectUnacknowledgedCount = activeWork.filter((item) => item.source === "direct" && item.staleDispatchUnacknowledged).length;
|
|
19537
|
-
return {
|
|
19538
|
-
totalActiveCount: activeWork.length,
|
|
19539
|
-
queueActiveCount: sourceCounts.queue,
|
|
19540
|
-
directActiveCount: sourceCounts.direct,
|
|
19541
|
-
awaitingApprovalCount: statusCounts.awaiting_approval,
|
|
19542
|
-
generatingCount: statusCounts.generating,
|
|
19543
|
-
failedCount: statusCounts.failed,
|
|
19544
|
-
idleCount: statusCounts.idle,
|
|
19545
|
-
sourceCounts,
|
|
19546
|
-
statusCounts,
|
|
19547
|
-
staleDirectCount,
|
|
19548
|
-
...staleDirectUnacknowledgedCount > 0 ? { staleDirectUnacknowledgedCount } : {},
|
|
19549
|
-
...staleDirectCount > 0 ? { staleDirectNote: "Stale direct records are orphaned ledger entries whose node/session no longer exists. They are historical recovery evidence only \u2014 not active or unresolved work. The queue (source: queue) is authoritative for pending/assigned tasks." } : {}
|
|
19550
|
-
};
|
|
19551
|
-
}
|
|
19552
|
-
function buildMeshActiveWork(opts) {
|
|
19553
|
-
const now = opts.now ?? Date.now();
|
|
19554
|
-
const records = [];
|
|
19555
|
-
const staleDirectWork = [];
|
|
19556
|
-
const terminalDirectWork = [];
|
|
19557
|
-
for (const task of opts.queue || []) {
|
|
19558
|
-
if (task.status !== "pending" && task.status !== "assigned") continue;
|
|
19559
|
-
const { title, summary: summary2 } = summarizeMessage(task.message || "");
|
|
19560
|
-
records.push({
|
|
19561
|
-
taskId: task.id,
|
|
19562
|
-
source: "queue",
|
|
19563
|
-
status: task.status,
|
|
19564
|
-
nodeId: task.assignedNodeId || task.targetNodeId,
|
|
19565
|
-
sessionId: task.assignedSessionId || task.targetSessionId,
|
|
19566
|
-
taskTitle: title,
|
|
19567
|
-
taskSummary: summary2,
|
|
19568
|
-
message: task.message,
|
|
19569
|
-
taskMode: task.taskMode,
|
|
19570
|
-
createdAt: task.createdAt,
|
|
19571
|
-
updatedAt: task.updatedAt,
|
|
19572
|
-
dispatchedAt: task.dispatchTimestamp,
|
|
19573
|
-
elapsedMs: elapsedSince(task.dispatchTimestamp || task.createdAt, now)
|
|
19574
|
-
});
|
|
19575
|
-
}
|
|
19576
|
-
if (opts.directDispatches !== void 0) {
|
|
19577
|
-
const dbTaskIds = new Set(opts.directDispatches.map((d) => d.taskId));
|
|
19578
|
-
for (const dispatch of opts.directDispatches) {
|
|
19579
|
-
const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId ?? void 0, dispatch.sessionId ?? void 0);
|
|
19580
|
-
const dbStatus = dispatch.status;
|
|
19581
|
-
const isTerminal = dbStatus === "completed" || dbStatus === "failed" || dbStatus === "stale";
|
|
19582
|
-
const status = isTerminal ? dbStatus === "completed" ? "idle" : "failed" : live.status || (dbStatus === "acked" ? "generating" : "assigned");
|
|
19583
|
-
const isNoTransition = !isTerminal && !live.status;
|
|
19584
|
-
const isIdleUnacknowledged = status === "idle" && !isTerminal;
|
|
19585
|
-
const ledgerOnlyStaleReason = !isTerminal && (isIdleUnacknowledged || isNoTransition || dispatch.dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
|
|
19586
|
-
const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
|
|
19587
|
-
const { title, summary: summary2 } = summarizeMessage(dispatch.message || "");
|
|
19588
|
-
const record = {
|
|
19589
|
-
taskId: dispatch.taskId,
|
|
19590
|
-
source: "direct",
|
|
19591
|
-
status,
|
|
19592
|
-
nodeId: dispatch.nodeId ?? void 0,
|
|
19593
|
-
sessionId: dispatch.sessionId ?? void 0,
|
|
19594
|
-
providerType: dispatch.providerType ?? void 0,
|
|
19595
|
-
taskTitle: title,
|
|
19596
|
-
taskSummary: summary2,
|
|
19597
|
-
message: dispatch.message,
|
|
19598
|
-
taskMode: dispatch.taskMode ?? void 0,
|
|
19599
|
-
createdAt: dispatch.dispatchedAt,
|
|
19600
|
-
updatedAt: dispatch.updatedAt,
|
|
19601
|
-
dispatchedAt: dispatch.dispatchedAt,
|
|
19602
|
-
elapsedMs: elapsedSince(dispatch.dispatchedAt, now),
|
|
19603
|
-
terminal: isTerminal,
|
|
19604
|
-
terminalKind: isTerminal ? dbStatus === "completed" ? "task_completed" : "task_failed" : void 0,
|
|
19605
|
-
terminalAt: isTerminal ? dispatch.updatedAt : void 0,
|
|
19606
|
-
staleReason: live.staleReason || ledgerOnlyStaleReason,
|
|
19607
|
-
...isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}
|
|
19608
|
-
};
|
|
19609
|
-
if (isTerminal) {
|
|
19610
|
-
terminalDirectWork.push(record);
|
|
19611
|
-
if (opts.includeTerminalDirect !== true) continue;
|
|
19612
|
-
}
|
|
19613
|
-
if ((live.staleReason || ledgerOnlyStaleReason) && !isTerminal) {
|
|
19614
|
-
staleDirectWork.push(record);
|
|
19615
|
-
continue;
|
|
19616
|
-
}
|
|
19617
|
-
records.push(record);
|
|
19618
|
-
}
|
|
19619
|
-
const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
19620
|
-
const terminals = ledgerEntries.filter((entry) => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === "task_approval_needed");
|
|
19621
|
-
for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
|
|
19622
|
-
const taskId = directDispatchTaskId(dispatch);
|
|
19623
|
-
if (dbTaskIds.has(taskId)) continue;
|
|
19624
|
-
const terminal = terminals.filter((entry) => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime()).find((entry) => terminalMatchesDispatch(entry, dispatch, taskId));
|
|
19625
|
-
const terminalStatus = terminal ? statusFromTerminal(terminal) : void 0;
|
|
19626
|
-
const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
|
|
19627
|
-
const status = terminalStatus || live.status || "assigned";
|
|
19628
|
-
const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
|
|
19629
|
-
const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
|
|
19630
|
-
const isNoTransition = !terminalStatus && !live.status;
|
|
19631
|
-
const isIdleUnacknowledged = status === "idle";
|
|
19632
|
-
const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
|
|
19633
|
-
const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
|
|
19634
|
-
const { title, summary: summary2 } = summarizeMessage(message);
|
|
19635
|
-
const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
|
|
19636
|
-
const record = {
|
|
19637
|
-
taskId,
|
|
19638
|
-
source: "direct",
|
|
19639
|
-
status,
|
|
19640
|
-
nodeId: dispatch.nodeId,
|
|
19641
|
-
sessionId: dispatch.sessionId,
|
|
19642
|
-
providerType: dispatch.providerType || readString6(dispatch.payload?.providerType),
|
|
19643
|
-
taskTitle: readString6(dispatch.payload?.taskTitle) || title,
|
|
19644
|
-
taskSummary: readString6(dispatch.payload?.taskSummary) || summary2,
|
|
19645
|
-
message,
|
|
19646
|
-
taskMode: readString6(dispatch.payload?.taskMode),
|
|
19647
|
-
createdAt: dispatch.timestamp,
|
|
19648
|
-
updatedAt: terminal?.timestamp || dispatch.timestamp,
|
|
19649
|
-
dispatchedAt: dispatch.timestamp,
|
|
19650
|
-
elapsedMs: elapsedSince(dispatch.timestamp, now),
|
|
19651
|
-
terminal: terminalRow,
|
|
19652
|
-
terminalKind: terminal?.kind,
|
|
19653
|
-
terminalAt: terminal?.timestamp,
|
|
19654
|
-
staleReason: live.staleReason || ledgerOnlyStaleReason,
|
|
19655
|
-
...isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}
|
|
19656
|
-
};
|
|
19657
|
-
if (terminalRow) {
|
|
19658
|
-
terminalDirectWork.push(record);
|
|
19659
|
-
if (opts.includeTerminalDirect !== true) continue;
|
|
19660
|
-
}
|
|
19661
|
-
if ((live.staleReason || ledgerOnlyStaleReason) && !terminalRow) {
|
|
19662
|
-
staleDirectWork.push(record);
|
|
19663
|
-
continue;
|
|
19664
|
-
}
|
|
19665
|
-
records.push(record);
|
|
19666
|
-
}
|
|
19667
|
-
} else {
|
|
19668
|
-
const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
19669
|
-
const terminals = ledgerEntries.filter((entry) => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === "task_approval_needed");
|
|
19670
|
-
for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
|
|
19671
|
-
const taskId = directDispatchTaskId(dispatch);
|
|
19672
|
-
const terminal = terminals.filter((entry) => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime()).find((entry) => terminalMatchesDispatch(entry, dispatch, taskId));
|
|
19673
|
-
const terminalStatus = terminal ? statusFromTerminal(terminal) : void 0;
|
|
19674
|
-
const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
|
|
19675
|
-
const status = terminalStatus || live.status || "assigned";
|
|
19676
|
-
const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
|
|
19677
|
-
const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
|
|
19678
|
-
const isNoTransition = !terminalStatus && !live.status;
|
|
19679
|
-
const isIdleUnacknowledged = status === "idle";
|
|
19680
|
-
const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
|
|
19681
|
-
const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
|
|
19682
|
-
const { title, summary: summary2 } = summarizeMessage(message);
|
|
19683
|
-
const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
|
|
19684
|
-
const record = {
|
|
19685
|
-
taskId,
|
|
19686
|
-
source: "direct",
|
|
19687
|
-
status,
|
|
19688
|
-
nodeId: dispatch.nodeId,
|
|
19689
|
-
sessionId: dispatch.sessionId,
|
|
19690
|
-
providerType: dispatch.providerType || readString6(dispatch.payload?.providerType),
|
|
19691
|
-
taskTitle: readString6(dispatch.payload?.taskTitle) || title,
|
|
19692
|
-
taskSummary: readString6(dispatch.payload?.taskSummary) || summary2,
|
|
19693
|
-
message,
|
|
19694
|
-
taskMode: readString6(dispatch.payload?.taskMode),
|
|
19695
|
-
createdAt: dispatch.timestamp,
|
|
19696
|
-
updatedAt: terminal?.timestamp || dispatch.timestamp,
|
|
19697
|
-
dispatchedAt: dispatch.timestamp,
|
|
19698
|
-
elapsedMs: elapsedSince(dispatch.timestamp, now),
|
|
19699
|
-
terminal: terminalRow,
|
|
19700
|
-
terminalKind: terminal?.kind,
|
|
19701
|
-
terminalAt: terminal?.timestamp,
|
|
19702
|
-
staleReason: live.staleReason || ledgerOnlyStaleReason,
|
|
19703
|
-
...isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}
|
|
19704
|
-
};
|
|
19705
|
-
if (terminalRow) {
|
|
19706
|
-
terminalDirectWork.push(record);
|
|
19707
|
-
if (opts.includeTerminalDirect !== true) continue;
|
|
19708
|
-
}
|
|
19709
|
-
if ((live.staleReason || ledgerOnlyStaleReason) && !terminalRow) {
|
|
19710
|
-
staleDirectWork.push(record);
|
|
19711
|
-
continue;
|
|
19712
|
-
}
|
|
19713
|
-
records.push(record);
|
|
19714
|
-
}
|
|
19715
|
-
}
|
|
19716
|
-
records.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
19717
|
-
staleDirectWork.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
19718
|
-
terminalDirectWork.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
19719
|
-
const summary = buildMeshActiveWorkSummary(records);
|
|
19720
|
-
summary.staleDirectCount = staleDirectWork.length;
|
|
19721
|
-
const unacknowledgedCount = staleDirectWork.filter((r) => r.staleDispatchUnacknowledged).length;
|
|
19722
|
-
if (unacknowledgedCount > 0) {
|
|
19723
|
-
summary.staleDirectUnacknowledgedCount = unacknowledgedCount;
|
|
19724
|
-
}
|
|
19725
|
-
const staleDirectWorkNote = staleDirectWork.length > 0 ? unacknowledgedCount > 0 && unacknowledgedCount === staleDirectWork.length ? `${unacknowledgedCount} direct dispatch(es) were not acknowledged by the target session \u2014 the session received the agent_command but never transitioned to generating. This is a fresh dispatch failure, not historical noise. Recovery: launch a fresh session on the same node and retry the task, or use mesh_enqueue_task for queue-based assignment.` : unacknowledgedCount > 0 ? `${unacknowledgedCount} of ${staleDirectWork.length} stale direct record(s) are fresh unacknowledged dispatch failures (session still live but never transitioned to generating); the rest are orphaned historical entries whose node/session no longer exists. Fresh unacknowledged dispatches need recovery: launch a fresh session and retry. Orphaned entries are historical evidence only \u2014 not active or unresolved work.` : "These are orphaned ledger entries whose original node or session no longer exists in the live mesh. They are historical/recovery evidence only \u2014 not active or unresolved work. Do not treat staleDirectCount as a status mismatch; use the queue (source: queue) as authoritative for pending/assigned tasks." : void 0;
|
|
19726
|
-
if (staleDirectWorkNote) {
|
|
19727
|
-
summary.staleDirectNote = staleDirectWorkNote;
|
|
19728
|
-
}
|
|
19729
|
-
return { activeWork: records, staleDirectWork, staleDirectWorkNote, terminalDirectWork, summary };
|
|
19730
|
-
}
|
|
19731
|
-
var PRUNABLE_ORPHAN_STALE_REASONS = /* @__PURE__ */ new Set([
|
|
19732
|
-
"direct task node is no longer in the live mesh",
|
|
19733
|
-
"direct task session is not present in live session records",
|
|
19734
|
-
"direct task has no node id"
|
|
19735
|
-
]);
|
|
19736
|
-
function classifyStaleDirectForPrune(record, opts = {}) {
|
|
19737
|
-
if (record.staleDispatchUnacknowledged === true) return "preserve_unacknowledged";
|
|
19738
|
-
if (record.terminal === true) return opts.includeTerminal ? "prunable_terminal" : "preserve_active";
|
|
19739
|
-
if (record.staleReason && PRUNABLE_ORPHAN_STALE_REASONS.has(record.staleReason)) return "prunable_orphan";
|
|
19740
|
-
return "preserve_active";
|
|
19741
|
-
}
|
|
19742
|
-
function buildCompactStaleDirectWorkSummary(staleDirectWork, opts = {}) {
|
|
19743
|
-
const sampleLimit = Math.max(0, Math.min(10, Math.floor(opts.sampleLimit ?? 3)));
|
|
19744
|
-
const reasonCounts = {};
|
|
19745
|
-
for (const entry of staleDirectWork) {
|
|
19746
|
-
const reason = entry.staleReason || "unknown";
|
|
19747
|
-
reasonCounts[reason] = (reasonCounts[reason] || 0) + 1;
|
|
19748
|
-
}
|
|
19749
|
-
return {
|
|
19750
|
-
count: staleDirectWork.length,
|
|
19751
|
-
sampleLimit,
|
|
19752
|
-
sample: staleDirectWork.slice(0, sampleLimit).map((entry) => ({
|
|
19753
|
-
taskId: entry.taskId,
|
|
19754
|
-
status: entry.status,
|
|
19755
|
-
nodeId: entry.nodeId,
|
|
19756
|
-
sessionId: entry.sessionId,
|
|
19757
|
-
taskTitle: entry.taskTitle,
|
|
19758
|
-
createdAt: entry.createdAt,
|
|
19759
|
-
staleReason: entry.staleReason
|
|
19760
|
-
})),
|
|
19761
|
-
reasonCounts,
|
|
19762
|
-
detailHint: opts.detailHint || "Stale direct records are historical recovery evidence only. Use mesh_task_history for full ledger details, or request includeStaleDirectWorkDetails when supported by the caller.",
|
|
19763
|
-
...opts.note ? { note: opts.note } : {}
|
|
19764
|
-
};
|
|
19765
|
-
}
|
|
19766
|
-
|
|
19767
|
-
// src/index.ts
|
|
20245
|
+
init_mesh_active_work();
|
|
19768
20246
|
init_mesh_refine_status();
|
|
19769
20247
|
init_mesh_host_ownership();
|
|
19770
20248
|
init_mesh_events();
|
|
@@ -19881,8 +20359,8 @@ var P2pRelayFailureError = class extends Error {
|
|
|
19881
20359
|
};
|
|
19882
20360
|
|
|
19883
20361
|
// src/config/state-store.ts
|
|
19884
|
-
var
|
|
19885
|
-
var
|
|
20362
|
+
var import_fs12 = require("fs");
|
|
20363
|
+
var import_path10 = require("path");
|
|
19886
20364
|
init_config();
|
|
19887
20365
|
var DEFAULT_STATE = {
|
|
19888
20366
|
recentActivity: [],
|
|
@@ -19896,7 +20374,7 @@ function isPlainObject2(value) {
|
|
|
19896
20374
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
19897
20375
|
}
|
|
19898
20376
|
function getStatePath() {
|
|
19899
|
-
return (0,
|
|
20377
|
+
return (0, import_path10.join)(getConfigDir(), "state.json");
|
|
19900
20378
|
}
|
|
19901
20379
|
function normalizeState(raw) {
|
|
19902
20380
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -19932,11 +20410,11 @@ function normalizeState(raw) {
|
|
|
19932
20410
|
}
|
|
19933
20411
|
function loadState() {
|
|
19934
20412
|
const statePath = getStatePath();
|
|
19935
|
-
if (!(0,
|
|
20413
|
+
if (!(0, import_fs12.existsSync)(statePath)) {
|
|
19936
20414
|
return { ...DEFAULT_STATE };
|
|
19937
20415
|
}
|
|
19938
20416
|
try {
|
|
19939
|
-
const raw = (0,
|
|
20417
|
+
const raw = (0, import_fs12.readFileSync)(statePath, "utf-8");
|
|
19940
20418
|
return normalizeState(JSON.parse(raw));
|
|
19941
20419
|
} catch {
|
|
19942
20420
|
return { ...DEFAULT_STATE };
|
|
@@ -19945,7 +20423,7 @@ function loadState() {
|
|
|
19945
20423
|
function saveState(state) {
|
|
19946
20424
|
const statePath = getStatePath();
|
|
19947
20425
|
const normalized = normalizeState(state);
|
|
19948
|
-
(0,
|
|
20426
|
+
(0, import_fs12.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
19949
20427
|
}
|
|
19950
20428
|
function resetState() {
|
|
19951
20429
|
saveState({ ...DEFAULT_STATE });
|
|
@@ -19954,7 +20432,7 @@ function resetState() {
|
|
|
19954
20432
|
// src/detection/ide-detector.ts
|
|
19955
20433
|
var import_child_process2 = require("child_process");
|
|
19956
20434
|
var import_util = require("util");
|
|
19957
|
-
var
|
|
20435
|
+
var import_fs13 = require("fs");
|
|
19958
20436
|
var import_os2 = require("os");
|
|
19959
20437
|
var path13 = __toESM(require("path"));
|
|
19960
20438
|
|
|
@@ -20035,7 +20513,7 @@ function findCliCommand(command) {
|
|
|
20035
20513
|
if (path13.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
20036
20514
|
const candidate = trimmed.startsWith("~") ? path13.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
|
|
20037
20515
|
const resolved = path13.isAbsolute(candidate) ? candidate : path13.resolve(candidate);
|
|
20038
|
-
return (0,
|
|
20516
|
+
return (0, import_fs13.existsSync)(resolved) ? resolved : null;
|
|
20039
20517
|
}
|
|
20040
20518
|
const isWin = (0, import_os2.platform)() === "win32";
|
|
20041
20519
|
const paths = (process.env.PATH || "").split(isWin ? ";" : ":");
|
|
@@ -20045,8 +20523,8 @@ function findCliCommand(command) {
|
|
|
20045
20523
|
for (const ext of exes) {
|
|
20046
20524
|
const fullPath = path13.join(p, trimmed + ext);
|
|
20047
20525
|
try {
|
|
20048
|
-
if ((0,
|
|
20049
|
-
const stat2 = (0,
|
|
20526
|
+
if ((0, import_fs13.existsSync)(fullPath)) {
|
|
20527
|
+
const stat2 = (0, import_fs13.statSync)(fullPath);
|
|
20050
20528
|
if (stat2.isFile() && (isWin || stat2.mode & 73)) {
|
|
20051
20529
|
return fullPath;
|
|
20052
20530
|
}
|
|
@@ -20064,9 +20542,9 @@ function checkPathExists(paths) {
|
|
|
20064
20542
|
if (normalized.includes("*")) {
|
|
20065
20543
|
const username = home.split(/[\\/]/).pop() || "";
|
|
20066
20544
|
const resolved = normalized.replace("*", username);
|
|
20067
|
-
if ((0,
|
|
20545
|
+
if ((0, import_fs13.existsSync)(resolved)) return resolved;
|
|
20068
20546
|
} else {
|
|
20069
|
-
if ((0,
|
|
20547
|
+
if ((0, import_fs13.existsSync)(normalized)) return normalized;
|
|
20070
20548
|
}
|
|
20071
20549
|
}
|
|
20072
20550
|
return null;
|
|
@@ -20080,7 +20558,7 @@ async function detectIDEs(providerLoader) {
|
|
|
20080
20558
|
let resolvedCli = cliPath;
|
|
20081
20559
|
if (!resolvedCli && appPath && os30 === "darwin") {
|
|
20082
20560
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
20083
|
-
if ((0,
|
|
20561
|
+
if ((0, import_fs13.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
20084
20562
|
}
|
|
20085
20563
|
if (!resolvedCli && appPath && os30 === "win32") {
|
|
20086
20564
|
const { dirname: dirname17 } = await import("path");
|
|
@@ -20093,7 +20571,7 @@ async function detectIDEs(providerLoader) {
|
|
|
20093
20571
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
20094
20572
|
];
|
|
20095
20573
|
for (const c of candidates) {
|
|
20096
|
-
if ((0,
|
|
20574
|
+
if ((0, import_fs13.existsSync)(c)) {
|
|
20097
20575
|
resolvedCli = c;
|
|
20098
20576
|
break;
|
|
20099
20577
|
}
|
|
@@ -21638,8 +22116,8 @@ init_contracts();
|
|
|
21638
22116
|
// src/providers/status-monitor.ts
|
|
21639
22117
|
var DEFAULT_MONITOR_CONFIG = {
|
|
21640
22118
|
approvalAlert: true,
|
|
21641
|
-
|
|
21642
|
-
|
|
22119
|
+
noProgressAlert: true,
|
|
22120
|
+
noProgressThresholdSec: 180,
|
|
21643
22121
|
// 3 minutes
|
|
21644
22122
|
alertCooldownSec: 60
|
|
21645
22123
|
// 1 minute cooldown
|
|
@@ -21648,7 +22126,7 @@ var StatusMonitor = class {
|
|
|
21648
22126
|
config;
|
|
21649
22127
|
lastAlertTime = /* @__PURE__ */ new Map();
|
|
21650
22128
|
generatingStartTimes = /* @__PURE__ */ new Map();
|
|
21651
|
-
|
|
22129
|
+
noProgressAlerted = /* @__PURE__ */ new Map();
|
|
21652
22130
|
lastProgressFingerprint = /* @__PURE__ */ new Map();
|
|
21653
22131
|
lastProgressChangeAt = /* @__PURE__ */ new Map();
|
|
21654
22132
|
constructor(config) {
|
|
@@ -21666,7 +22144,7 @@ var StatusMonitor = class {
|
|
|
21666
22144
|
* Check status transition → return notification event array.
|
|
21667
22145
|
* Called from each onTick() or detectStatusTransition().
|
|
21668
22146
|
*/
|
|
21669
|
-
check(agentKey, status, now, progressFingerprint) {
|
|
22147
|
+
check(agentKey, status, now, progressFingerprint, approvalPending) {
|
|
21670
22148
|
const events = [];
|
|
21671
22149
|
if (this.config.approvalAlert && status === "waiting_approval") {
|
|
21672
22150
|
if (this.shouldAlert(agentKey + ":approval", now)) {
|
|
@@ -21679,9 +22157,16 @@ var StatusMonitor = class {
|
|
|
21679
22157
|
}
|
|
21680
22158
|
}
|
|
21681
22159
|
if (status === "generating" || status === "streaming") {
|
|
22160
|
+
if (approvalPending) {
|
|
22161
|
+
this.generatingStartTimes.set(agentKey, now);
|
|
22162
|
+
this.lastProgressFingerprint.set(agentKey, progressFingerprint ?? "");
|
|
22163
|
+
this.lastProgressChangeAt.set(agentKey, now);
|
|
22164
|
+
this.noProgressAlerted.set(agentKey, false);
|
|
22165
|
+
return events;
|
|
22166
|
+
}
|
|
21682
22167
|
if (!this.generatingStartTimes.has(agentKey)) {
|
|
21683
22168
|
this.generatingStartTimes.set(agentKey, now);
|
|
21684
|
-
this.
|
|
22169
|
+
this.noProgressAlerted.set(agentKey, false);
|
|
21685
22170
|
const initialFingerprint = progressFingerprint ?? "";
|
|
21686
22171
|
this.lastProgressFingerprint.set(agentKey, initialFingerprint);
|
|
21687
22172
|
this.lastProgressChangeAt.set(agentKey, now);
|
|
@@ -21691,17 +22176,17 @@ var StatusMonitor = class {
|
|
|
21691
22176
|
if (previousFingerprint !== currentFingerprint) {
|
|
21692
22177
|
this.lastProgressFingerprint.set(agentKey, currentFingerprint);
|
|
21693
22178
|
this.lastProgressChangeAt.set(agentKey, now);
|
|
21694
|
-
this.
|
|
22179
|
+
this.noProgressAlerted.set(agentKey, false);
|
|
21695
22180
|
}
|
|
21696
|
-
if (this.config.
|
|
22181
|
+
if (this.config.noProgressAlert) {
|
|
21697
22182
|
const progressChangedAt = this.lastProgressChangeAt.get(agentKey) || this.generatingStartTimes.get(agentKey);
|
|
21698
22183
|
const elapsedSec = Math.round((now - progressChangedAt) / 1e3);
|
|
21699
|
-
const alreadyAlerted = this.
|
|
21700
|
-
if (elapsedSec > this.config.
|
|
21701
|
-
if (this.shouldAlert(agentKey + ":
|
|
21702
|
-
this.
|
|
22184
|
+
const alreadyAlerted = this.noProgressAlerted.get(agentKey) === true;
|
|
22185
|
+
if (elapsedSec > this.config.noProgressThresholdSec && !alreadyAlerted) {
|
|
22186
|
+
if (this.shouldAlert(agentKey + ":no_progress", now)) {
|
|
22187
|
+
this.noProgressAlerted.set(agentKey, true);
|
|
21703
22188
|
events.push({
|
|
21704
|
-
type: "monitor:
|
|
22189
|
+
type: "monitor:no_progress",
|
|
21705
22190
|
agentKey,
|
|
21706
22191
|
elapsedSec,
|
|
21707
22192
|
timestamp: now,
|
|
@@ -21712,7 +22197,7 @@ var StatusMonitor = class {
|
|
|
21712
22197
|
}
|
|
21713
22198
|
} else {
|
|
21714
22199
|
this.generatingStartTimes.delete(agentKey);
|
|
21715
|
-
this.
|
|
22200
|
+
this.noProgressAlerted.delete(agentKey);
|
|
21716
22201
|
this.lastProgressFingerprint.delete(agentKey);
|
|
21717
22202
|
this.lastProgressChangeAt.delete(agentKey);
|
|
21718
22203
|
}
|
|
@@ -21731,7 +22216,7 @@ var StatusMonitor = class {
|
|
|
21731
22216
|
reset(agentKey) {
|
|
21732
22217
|
if (agentKey) {
|
|
21733
22218
|
this.generatingStartTimes.delete(agentKey);
|
|
21734
|
-
this.
|
|
22219
|
+
this.noProgressAlerted.delete(agentKey);
|
|
21735
22220
|
this.lastProgressFingerprint.delete(agentKey);
|
|
21736
22221
|
this.lastProgressChangeAt.delete(agentKey);
|
|
21737
22222
|
for (const k of this.lastAlertTime.keys()) {
|
|
@@ -21739,7 +22224,7 @@ var StatusMonitor = class {
|
|
|
21739
22224
|
}
|
|
21740
22225
|
} else {
|
|
21741
22226
|
this.generatingStartTimes.clear();
|
|
21742
|
-
this.
|
|
22227
|
+
this.noProgressAlerted.clear();
|
|
21743
22228
|
this.lastProgressFingerprint.clear();
|
|
21744
22229
|
this.lastProgressChangeAt.clear();
|
|
21745
22230
|
this.lastAlertTime.clear();
|
|
@@ -23562,8 +24047,8 @@ var ExtensionProviderInstance = class {
|
|
|
23562
24047
|
this.settings = context.settings || {};
|
|
23563
24048
|
this.monitor.updateConfig({
|
|
23564
24049
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
23565
|
-
|
|
23566
|
-
|
|
24050
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
24051
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
23567
24052
|
});
|
|
23568
24053
|
}
|
|
23569
24054
|
async onTick() {
|
|
@@ -23654,8 +24139,8 @@ var ExtensionProviderInstance = class {
|
|
|
23654
24139
|
this.settings = { ...this.settings, ...newSettings };
|
|
23655
24140
|
this.monitor.updateConfig({
|
|
23656
24141
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
23657
|
-
|
|
23658
|
-
|
|
24142
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
24143
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
23659
24144
|
});
|
|
23660
24145
|
}
|
|
23661
24146
|
/** Query UUID instanceId */
|
|
@@ -23715,7 +24200,8 @@ var ExtensionProviderInstance = class {
|
|
|
23715
24200
|
phase: agentStatus === "idle" && (previousStatus === "generating" || previousStatus === "waiting_approval") ? "turn_completed" : "immediate"
|
|
23716
24201
|
});
|
|
23717
24202
|
const agentKey = `${this.type}:ext`;
|
|
23718
|
-
const
|
|
24203
|
+
const approvalPending = agentStatus === "waiting_approval";
|
|
24204
|
+
const monitorEvents = this.monitor.check(agentKey, agentStatus, now, progressFingerprint, approvalPending);
|
|
23719
24205
|
for (const me of monitorEvents) {
|
|
23720
24206
|
this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
|
|
23721
24207
|
}
|
|
@@ -23930,7 +24416,7 @@ init_contracts();
|
|
|
23930
24416
|
var CHAT_CONTRACT_VERSION_V1 = "1.0";
|
|
23931
24417
|
|
|
23932
24418
|
// src/providers/read-chat-contract.ts
|
|
23933
|
-
var VALID_STATUSES = ["idle", "generating", "waiting_approval", "error", "panel_hidden", "starting", "streaming", "long_generating"];
|
|
24419
|
+
var VALID_STATUSES = ["idle", "generating", "waiting_approval", "error", "panel_hidden", "starting", "streaming", "no_progress", "long_generating"];
|
|
23934
24420
|
var VALID_ROLES = ["user", "assistant", "system", "human"];
|
|
23935
24421
|
var VALID_BUBBLE_STATES = ["draft", "streaming", "final", "removed"];
|
|
23936
24422
|
var VALID_TURN_STATUSES = ["open", "waiting_approval", "complete", "error"];
|
|
@@ -24197,8 +24683,8 @@ var IdeProviderInstance = class {
|
|
|
24197
24683
|
this.settings = context.settings || {};
|
|
24198
24684
|
this.monitor.updateConfig({
|
|
24199
24685
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
24200
|
-
|
|
24201
|
-
|
|
24686
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
24687
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
24202
24688
|
});
|
|
24203
24689
|
}
|
|
24204
24690
|
async onTick() {
|
|
@@ -24325,8 +24811,8 @@ var IdeProviderInstance = class {
|
|
|
24325
24811
|
this.settings = { ...this.settings, ...newSettings };
|
|
24326
24812
|
this.monitor.updateConfig({
|
|
24327
24813
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
24328
|
-
|
|
24329
|
-
|
|
24814
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
24815
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
24330
24816
|
});
|
|
24331
24817
|
}
|
|
24332
24818
|
// ─── Extension manage ─────────────────────────────
|
|
@@ -24457,7 +24943,7 @@ var IdeProviderInstance = class {
|
|
|
24457
24943
|
const persistedMessages = chat.messages || messages;
|
|
24458
24944
|
if (persistedMessages.length > 0) {
|
|
24459
24945
|
let toSave = persistedMessages;
|
|
24460
|
-
if (chat.status === "generating" || chat.status === "long_generating") {
|
|
24946
|
+
if (chat.status === "generating" || chat.status === "no_progress" || chat.status === "long_generating") {
|
|
24461
24947
|
const lastIdx = toSave.length - 1;
|
|
24462
24948
|
if (lastIdx >= 0 && toSave[lastIdx].role === "assistant") {
|
|
24463
24949
|
toSave = toSave.slice(0, lastIdx);
|
|
@@ -24527,7 +25013,8 @@ var IdeProviderInstance = class {
|
|
|
24527
25013
|
if (rawAgentStatus === "waiting_approval" && autoApproveActive && !this.autoApproveBusy) {
|
|
24528
25014
|
this.autoApproveViaScript(chatData);
|
|
24529
25015
|
}
|
|
24530
|
-
const
|
|
25016
|
+
const approvalPending = rawAgentStatus === "waiting_approval";
|
|
25017
|
+
const monitorEvents = this.monitor.check(agentKey, agentStatus, now, progressFingerprint, approvalPending);
|
|
24531
25018
|
for (const me of monitorEvents) {
|
|
24532
25019
|
this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
|
|
24533
25020
|
}
|
|
@@ -27084,7 +27571,7 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
27084
27571
|
}
|
|
27085
27572
|
}
|
|
27086
27573
|
function isGeneratingLikeStatus(status) {
|
|
27087
|
-
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
27574
|
+
return status === "generating" || status === "streaming" || status === "no_progress" || status === "long_generating" || status === "starting";
|
|
27088
27575
|
}
|
|
27089
27576
|
function hasVisibleAssistantMessage(messages) {
|
|
27090
27577
|
if (!Array.isArray(messages)) return false;
|
|
@@ -31117,7 +31604,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
31117
31604
|
var os19 = __toESM(require("os"));
|
|
31118
31605
|
var path26 = __toESM(require("path"));
|
|
31119
31606
|
var crypto5 = __toESM(require("crypto"));
|
|
31120
|
-
var
|
|
31607
|
+
var import_fs15 = require("fs");
|
|
31121
31608
|
var import_child_process6 = require("child_process");
|
|
31122
31609
|
var import_chalk = __toESM(require("chalk"));
|
|
31123
31610
|
init_provider_cli_adapter();
|
|
@@ -33762,7 +34249,7 @@ function hasNonEmptyCliModalButtons(activeModal) {
|
|
|
33762
34249
|
return Array.isArray(buttons) && buttons.some((button) => String(button || "").trim().length > 0);
|
|
33763
34250
|
}
|
|
33764
34251
|
function isCliGeneratingLikeStatus(status) {
|
|
33765
|
-
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
34252
|
+
return status === "generating" || status === "streaming" || status === "no_progress" || status === "long_generating" || status === "starting";
|
|
33766
34253
|
}
|
|
33767
34254
|
function buildCliStructuredInputPrompt(input, options = {}) {
|
|
33768
34255
|
const promptParts = [];
|
|
@@ -33964,8 +34451,8 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
33964
34451
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
33965
34452
|
this.monitor.updateConfig({
|
|
33966
34453
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
33967
|
-
|
|
33968
|
-
|
|
34454
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
34455
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
33969
34456
|
});
|
|
33970
34457
|
if (context.serverConn) {
|
|
33971
34458
|
this.adapter.setServerConn(context.serverConn);
|
|
@@ -34112,7 +34599,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
34112
34599
|
if (parsedMessages.length > 0) {
|
|
34113
34600
|
const shouldSkipReplayPersist = this.suppressIdleHistoryReplay && adapterStatus.status === "idle" && parsedStatus?.status === "idle";
|
|
34114
34601
|
let messagesToSave = parsedMessages;
|
|
34115
|
-
if (!suppressStaleParsedBusyStatus && (parsedChatStatus === "generating" || parsedChatStatus === "long_generating")) {
|
|
34602
|
+
if (!suppressStaleParsedBusyStatus && (parsedChatStatus === "generating" || parsedChatStatus === "no_progress" || parsedChatStatus === "long_generating")) {
|
|
34116
34603
|
const lastIdx = messagesToSave.length - 1;
|
|
34117
34604
|
if (lastIdx >= 0 && messagesToSave[lastIdx]?.role === "assistant") {
|
|
34118
34605
|
messagesToSave = messagesToSave.slice(0, lastIdx);
|
|
@@ -34240,8 +34727,8 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
34240
34727
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
34241
34728
|
this.monitor.updateConfig({
|
|
34242
34729
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
34243
|
-
|
|
34244
|
-
|
|
34730
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
34731
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
34245
34732
|
});
|
|
34246
34733
|
}
|
|
34247
34734
|
/**
|
|
@@ -34973,10 +35460,11 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
34973
35460
|
phase: newStatus === "idle" && (previousStatus === "generating" || previousStatus === "waiting_approval") ? "turn_completed" : "immediate"
|
|
34974
35461
|
});
|
|
34975
35462
|
const agentKey = `${this.type}:cli`;
|
|
34976
|
-
const
|
|
35463
|
+
const approvalPending = rawStatus === "waiting_approval";
|
|
35464
|
+
const monitorEvents = this.monitor.check(agentKey, newStatus, now, progressFingerprint, approvalPending);
|
|
34977
35465
|
const monitorParsedStatus = parsedStatus;
|
|
34978
35466
|
for (const me of monitorEvents) {
|
|
34979
|
-
if (me.type === "monitor:
|
|
35467
|
+
if (me.type === "monitor:no_progress" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
|
|
34980
35468
|
this.pushEvent({
|
|
34981
35469
|
event: "agent:generating_completed",
|
|
34982
35470
|
chatTitle,
|
|
@@ -34987,7 +35475,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
34987
35475
|
providerType: this.type,
|
|
34988
35476
|
sessionId: this.instanceId,
|
|
34989
35477
|
providerSessionId: this.providerSessionId || null,
|
|
34990
|
-
reconciliationReason: "
|
|
35478
|
+
reconciliationReason: "no_progress_monitor_final_summary",
|
|
34991
35479
|
finalAssistantPresent: true
|
|
34992
35480
|
}
|
|
34993
35481
|
});
|
|
@@ -35664,8 +36152,8 @@ var AcpProviderInstance = class {
|
|
|
35664
36152
|
this.settings = context.settings || {};
|
|
35665
36153
|
this.monitor.updateConfig({
|
|
35666
36154
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
35667
|
-
|
|
35668
|
-
|
|
36155
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
36156
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
35669
36157
|
});
|
|
35670
36158
|
await this.spawnAgent();
|
|
35671
36159
|
}
|
|
@@ -35961,8 +36449,8 @@ var AcpProviderInstance = class {
|
|
|
35961
36449
|
this.settings = { ...this.settings, ...newSettings };
|
|
35962
36450
|
this.monitor.updateConfig({
|
|
35963
36451
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
35964
|
-
|
|
35965
|
-
|
|
36452
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
36453
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
35966
36454
|
});
|
|
35967
36455
|
this.log.info(`[${this.type}] Settings updated: ${Object.keys(newSettings).join(", ")}`);
|
|
35968
36456
|
}
|
|
@@ -36669,7 +37157,8 @@ ${rawInput}` : rawInput;
|
|
|
36669
37157
|
this.lastStatus = newStatus;
|
|
36670
37158
|
}
|
|
36671
37159
|
const agentKey = `${this.type}:acp`;
|
|
36672
|
-
const
|
|
37160
|
+
const approvalPending = newStatus === "waiting_approval";
|
|
37161
|
+
const monitorEvents = this.monitor.check(agentKey, newStatus, now, progressFingerprint, approvalPending);
|
|
36673
37162
|
for (const me of monitorEvents) {
|
|
36674
37163
|
this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
|
|
36675
37164
|
}
|
|
@@ -36731,7 +37220,7 @@ function commandExists(command) {
|
|
|
36731
37220
|
const trimmed = command.trim();
|
|
36732
37221
|
if (!trimmed) return false;
|
|
36733
37222
|
if (isExplicitCommand(trimmed)) {
|
|
36734
|
-
return (0,
|
|
37223
|
+
return (0, import_fs15.existsSync)(expandExecutable(trimmed));
|
|
36735
37224
|
}
|
|
36736
37225
|
try {
|
|
36737
37226
|
(0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -36743,7 +37232,7 @@ function commandExists(command) {
|
|
|
36743
37232
|
return false;
|
|
36744
37233
|
}
|
|
36745
37234
|
}
|
|
36746
|
-
var BUSY_AGENT_STATUSES = /* @__PURE__ */ new Set(["generating", "running", "streaming", "starting", "busy", "waiting", "waiting_approval", "long_generating"]);
|
|
37235
|
+
var BUSY_AGENT_STATUSES = /* @__PURE__ */ new Set(["generating", "running", "streaming", "starting", "busy", "waiting", "waiting_approval", "no_progress", "long_generating"]);
|
|
36747
37236
|
var ZERO_MESSAGE_STARTING_SEND_WAIT_MS = 2e3;
|
|
36748
37237
|
function normalizeAgentStatus(value) {
|
|
36749
37238
|
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
@@ -36867,10 +37356,10 @@ function hasConfigOverride(args, key) {
|
|
|
36867
37356
|
}
|
|
36868
37357
|
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
36869
37358
|
const baseDir = path26.join(os19.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
36870
|
-
(0,
|
|
37359
|
+
(0, import_fs15.mkdirSync)(baseDir, { recursive: true });
|
|
36871
37360
|
const workspaceHash = crypto5.createHash("sha256").update(path26.resolve(workspace || os19.tmpdir())).digest("hex").slice(0, 16);
|
|
36872
37361
|
const filePath = path26.join(baseDir, `${workspaceHash}.json`);
|
|
36873
|
-
(0,
|
|
37362
|
+
(0, import_fs15.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
36874
37363
|
return filePath;
|
|
36875
37364
|
}
|
|
36876
37365
|
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
@@ -41608,6 +42097,7 @@ function getAvailableIdeIds() {
|
|
|
41608
42097
|
init_config();
|
|
41609
42098
|
init_cli_detector();
|
|
41610
42099
|
init_git_status();
|
|
42100
|
+
init_change_impact_config();
|
|
41611
42101
|
init_dist();
|
|
41612
42102
|
init_logger();
|
|
41613
42103
|
|
|
@@ -41756,7 +42246,7 @@ function getRecentCommands(count = 50) {
|
|
|
41756
42246
|
cleanOldFiles();
|
|
41757
42247
|
|
|
41758
42248
|
// src/commands/router.ts
|
|
41759
|
-
var
|
|
42249
|
+
var yaml4 = __toESM(require("js-yaml"));
|
|
41760
42250
|
init_logger();
|
|
41761
42251
|
|
|
41762
42252
|
// src/logging/log-tail-reader.ts
|
|
@@ -42142,8 +42632,8 @@ function buildPreviewFreshness(repoRoot) {
|
|
|
42142
42632
|
init_mesh_refine_status();
|
|
42143
42633
|
|
|
42144
42634
|
// src/mesh/mesh-init.ts
|
|
42145
|
-
var
|
|
42146
|
-
var
|
|
42635
|
+
var import_fs16 = require("fs");
|
|
42636
|
+
var import_path11 = require("path");
|
|
42147
42637
|
var MESH_INIT_REFINE_CONFIG_PATH = MESH_REFINE_CONFIG_LOCATIONS[0];
|
|
42148
42638
|
var MESH_INIT_WORKTREE_BOOTSTRAP_CONFIG_PATH = MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS[0];
|
|
42149
42639
|
var CANDIDATE_STALE_INPUTS = [
|
|
@@ -42157,22 +42647,22 @@ var CANDIDATE_STALE_INPUTS = [
|
|
|
42157
42647
|
"requirements.txt"
|
|
42158
42648
|
];
|
|
42159
42649
|
function writeConfigFile(workspace, relativePath, config) {
|
|
42160
|
-
const target = (0,
|
|
42161
|
-
(0,
|
|
42162
|
-
(0,
|
|
42650
|
+
const target = (0, import_path11.join)(workspace, relativePath);
|
|
42651
|
+
(0, import_fs16.mkdirSync)((0, import_path11.dirname)(target), { recursive: true });
|
|
42652
|
+
(0, import_fs16.writeFileSync)(target, `${JSON.stringify(config, null, 2)}
|
|
42163
42653
|
`, "utf-8");
|
|
42164
42654
|
return target;
|
|
42165
42655
|
}
|
|
42166
42656
|
function suggestMeshWorktreeBootstrapConfig(workspace) {
|
|
42167
42657
|
const commands = [];
|
|
42168
|
-
const hasPackageJson = (0,
|
|
42169
|
-
const hasNpmLock = (0,
|
|
42658
|
+
const hasPackageJson = (0, import_fs16.existsSync)((0, import_path11.join)(workspace, "package.json"));
|
|
42659
|
+
const hasNpmLock = (0, import_fs16.existsSync)((0, import_path11.join)(workspace, "package-lock.json"));
|
|
42170
42660
|
if (hasPackageJson) {
|
|
42171
42661
|
commands.push(
|
|
42172
42662
|
hasNpmLock ? { command: "npm", args: ["ci"] } : { command: "npm", args: ["install"] }
|
|
42173
42663
|
);
|
|
42174
42664
|
}
|
|
42175
|
-
const staleInputs = CANDIDATE_STALE_INPUTS.filter((relative5) => (0,
|
|
42665
|
+
const staleInputs = CANDIDATE_STALE_INPUTS.filter((relative5) => (0, import_fs16.existsSync)((0, import_path11.join)(workspace, relative5)));
|
|
42176
42666
|
if (!commands.length) {
|
|
42177
42667
|
return { commands, staleInputs };
|
|
42178
42668
|
}
|
|
@@ -42240,7 +42730,7 @@ function runMeshInit(mesh, workspace, detected, options = {}) {
|
|
|
42240
42730
|
}
|
|
42241
42731
|
function applyConfigSuggestion(input) {
|
|
42242
42732
|
const { workspace, relativePath, existing, suggestedConfig, validate, write, overwrite } = input;
|
|
42243
|
-
const absolute = (0,
|
|
42733
|
+
const absolute = (0, import_path11.join)(workspace, relativePath);
|
|
42244
42734
|
if (existing !== void 0 && !overwrite) {
|
|
42245
42735
|
return { path: absolute, relativePath, written: false, skippedReason: "already_exists", config: existing };
|
|
42246
42736
|
}
|
|
@@ -42965,7 +43455,7 @@ async function maybeRunDaemonUpgradeHelperFromEnv() {
|
|
|
42965
43455
|
init_mesh_work_queue();
|
|
42966
43456
|
init_repo_mesh_types();
|
|
42967
43457
|
var import_os3 = require("os");
|
|
42968
|
-
var
|
|
43458
|
+
var import_path12 = require("path");
|
|
42969
43459
|
var fs26 = __toESM(require("fs"));
|
|
42970
43460
|
var import_node_child_process6 = require("child_process");
|
|
42971
43461
|
var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
|
|
@@ -44438,14 +44928,14 @@ function collectFastForwardGitlinkPaths(repoRoot, baseHead, branchHead) {
|
|
|
44438
44928
|
const baseCommit = readTreeObject(repoRoot, baseHead, path42);
|
|
44439
44929
|
const branchCommit = readTreeObject(repoRoot, branchHead, path42);
|
|
44440
44930
|
if (!baseCommit || !branchCommit) return false;
|
|
44441
|
-
return isSubmoduleFastForward((0,
|
|
44931
|
+
return isSubmoduleFastForward((0, import_path12.resolve)(repoRoot, path42), baseCommit, branchCommit);
|
|
44442
44932
|
});
|
|
44443
44933
|
}
|
|
44444
44934
|
function evaluateGitlinkTrivialFastForward(repoRoot, baseHead, branchHead) {
|
|
44445
44935
|
const changedGitlinks = readChangedGitlinkPaths(repoRoot, baseHead, branchHead).map((path42) => {
|
|
44446
44936
|
const baseCommit = readTreeObject(repoRoot, baseHead, path42);
|
|
44447
44937
|
const branchCommit = readTreeObject(repoRoot, branchHead, path42);
|
|
44448
|
-
const submoduleRepoPath = (0,
|
|
44938
|
+
const submoduleRepoPath = (0, import_path12.resolve)(repoRoot, path42);
|
|
44449
44939
|
const fastForward = !!baseCommit && !!branchCommit && isSubmoduleFastForward(submoduleRepoPath, baseCommit, branchCommit);
|
|
44450
44940
|
return { path: path42, baseCommit, branchCommit, fastForward };
|
|
44451
44941
|
});
|
|
@@ -44500,7 +44990,7 @@ function buildTreeWithGitlinksEqualized(repoRoot, commitish, paths, placeholderC
|
|
|
44500
44990
|
if (!tree) return void 0;
|
|
44501
44991
|
const updates = paths.map((path42) => `160000 commit ${placeholderCommit} ${path42}`).join("\n");
|
|
44502
44992
|
if (!updates) return tree;
|
|
44503
|
-
const tmpIndex = (0,
|
|
44993
|
+
const tmpIndex = (0, import_path12.join)(resolveGitDir(repoRoot), `adhdev-refine-eq-${commitish.slice(0, 12)}.index`);
|
|
44504
44994
|
const env = { ...process.env, GIT_INDEX_FILE: tmpIndex };
|
|
44505
44995
|
try {
|
|
44506
44996
|
(0, import_node_child_process6.execFileSync)("git", ["read-tree", tree], { cwd: repoRoot, env, stdio: "ignore" });
|
|
@@ -44575,7 +45065,7 @@ function synthesizeTrivialFastForwardMergeTree(repoRoot, baseHead, branchHead, g
|
|
|
44575
45065
|
if (!contentTree) return void 0;
|
|
44576
45066
|
const updates = branchGitlinks.map((entry) => `160000 commit ${entry.branchCommit} ${entry.path}`).join("\n");
|
|
44577
45067
|
if (!updates) return contentTree;
|
|
44578
|
-
const tmpIndex = (0,
|
|
45068
|
+
const tmpIndex = (0, import_path12.join)(resolveGitDir(repoRoot), `adhdev-refine-ff-${baseHead.slice(0, 12)}-${branchHead.slice(0, 12)}.index`);
|
|
44579
45069
|
const env = { ...process.env, GIT_INDEX_FILE: tmpIndex };
|
|
44580
45070
|
try {
|
|
44581
45071
|
(0, import_node_child_process6.execFileSync)("git", ["read-tree", contentTree], { cwd: repoRoot, env, stdio: "ignore" });
|
|
@@ -44713,7 +45203,7 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, opti
|
|
|
44713
45203
|
return match ? { commit: match[1], path: match[2] } : null;
|
|
44714
45204
|
}).filter((entry) => !!entry);
|
|
44715
45205
|
for (const gitlink of gitlinks) {
|
|
44716
|
-
const submodulePath = (0,
|
|
45206
|
+
const submodulePath = (0, import_path12.resolve)(repoRoot, gitlink.path);
|
|
44717
45207
|
const entry = {
|
|
44718
45208
|
path: gitlink.path,
|
|
44719
45209
|
commit: gitlink.commit,
|
|
@@ -44741,7 +45231,7 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, opti
|
|
|
44741
45231
|
try {
|
|
44742
45232
|
const imported = await importCommitFromWorktreeSubmodule(
|
|
44743
45233
|
submodulePath,
|
|
44744
|
-
(0,
|
|
45234
|
+
(0, import_path12.resolve)(options.worktreeRoot, gitlink.path),
|
|
44745
45235
|
gitlink.commit
|
|
44746
45236
|
);
|
|
44747
45237
|
if (imported) {
|
|
@@ -44953,19 +45443,19 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
44953
45443
|
...extras
|
|
44954
45444
|
});
|
|
44955
45445
|
const isPackageManagerValidation = (candidate) => {
|
|
44956
|
-
const command = (0,
|
|
45446
|
+
const command = (0, import_path12.basename)(candidate.command).replace(/\.(?:cmd|exe)$/i, "");
|
|
44957
45447
|
return ["npm", "pnpm", "yarn", "bun"].includes(command) && candidate.args.some((arg) => arg === "run" || arg === "test" || arg === "exec");
|
|
44958
45448
|
};
|
|
44959
45449
|
const dependenciesLikelyMissing = (cwd) => {
|
|
44960
|
-
if (!fs26.existsSync((0,
|
|
44961
|
-
if (fs26.existsSync((0,
|
|
44962
|
-
return ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"].some((lock) => fs26.existsSync((0,
|
|
45450
|
+
if (!fs26.existsSync((0, import_path12.join)(cwd, "package.json"))) return false;
|
|
45451
|
+
if (fs26.existsSync((0, import_path12.join)(cwd, "node_modules"))) return false;
|
|
45452
|
+
return ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"].some((lock) => fs26.existsSync((0, import_path12.join)(cwd, lock)));
|
|
44963
45453
|
};
|
|
44964
45454
|
if (runLegacyBootstrapCommands) {
|
|
44965
45455
|
summary.bootstrap = { stage: "legacy" };
|
|
44966
45456
|
for (const candidate of selection.bootstrapCommands) {
|
|
44967
45457
|
const startedAt = Date.now();
|
|
44968
|
-
const cwd = candidate.cwd ? (0,
|
|
45458
|
+
const cwd = candidate.cwd ? (0, import_path12.resolve)(workspace, candidate.cwd) : workspace;
|
|
44969
45459
|
const timeout = candidate.timeoutMs || REFINE_VALIDATION_TIMEOUT_MS;
|
|
44970
45460
|
try {
|
|
44971
45461
|
const result = await execFileAsync4(candidate.command, candidate.args, {
|
|
@@ -44993,7 +45483,7 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
44993
45483
|
}
|
|
44994
45484
|
for (const candidate of selection.commands) {
|
|
44995
45485
|
const startedAt = Date.now();
|
|
44996
|
-
const cwd = candidate.cwd ? (0,
|
|
45486
|
+
const cwd = candidate.cwd ? (0, import_path12.resolve)(workspace, candidate.cwd) : workspace;
|
|
44997
45487
|
const timeout = candidate.timeoutMs || REFINE_VALIDATION_TIMEOUT_MS;
|
|
44998
45488
|
const bootstrapProvidedDependencies = summary.bootstrap?.stage === "cached" || summary.bootstrap?.stage === "ran" || summary.bootstrap?.stage === "legacy";
|
|
44999
45489
|
if (!bootstrapProvidedDependencies && isPackageManagerValidation(candidate) && dependenciesLikelyMissing(cwd)) {
|
|
@@ -45039,7 +45529,7 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
45039
45529
|
return summary;
|
|
45040
45530
|
}
|
|
45041
45531
|
function loadYamlModule() {
|
|
45042
|
-
return
|
|
45532
|
+
return yaml4;
|
|
45043
45533
|
}
|
|
45044
45534
|
function getMcpServersKey(format) {
|
|
45045
45535
|
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
@@ -45056,13 +45546,13 @@ function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
|
45056
45546
|
}
|
|
45057
45547
|
function resolveHermesUserHome() {
|
|
45058
45548
|
const explicitHome = process.env.HERMES_HOME?.trim();
|
|
45059
|
-
return explicitHome || (0,
|
|
45549
|
+
return explicitHome || (0, import_path12.join)((0, import_os3.homedir)(), ".hermes");
|
|
45060
45550
|
}
|
|
45061
45551
|
function loadHermesCoordinatorBaseConfig(targetConfigPath) {
|
|
45062
45552
|
const sourceHome = resolveHermesUserHome();
|
|
45063
|
-
const sourceConfigPath = (0,
|
|
45553
|
+
const sourceConfigPath = (0, import_path12.join)(sourceHome, "config.yaml");
|
|
45064
45554
|
if (!fs26.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
45065
|
-
if ((0,
|
|
45555
|
+
if ((0, import_path12.resolve)(sourceConfigPath) === (0, import_path12.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
45066
45556
|
const parsed = parseMeshCoordinatorMcpConfig(fs26.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
|
|
45067
45557
|
const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
|
|
45068
45558
|
return { config: baseConfig, sourceHome, sourceConfigPath };
|
|
@@ -45096,10 +45586,10 @@ function stripHermesCoordinatorTempModelProviderOverrides(config) {
|
|
|
45096
45586
|
return sanitized;
|
|
45097
45587
|
}
|
|
45098
45588
|
function copyHermesCoordinatorCredentialFiles(sourceHome, targetHome) {
|
|
45099
|
-
if ((0,
|
|
45589
|
+
if ((0, import_path12.resolve)(sourceHome) === (0, import_path12.resolve)(targetHome)) return;
|
|
45100
45590
|
for (const fileName of [".env", "auth.json"]) {
|
|
45101
|
-
const sourcePath = (0,
|
|
45102
|
-
const targetPath = (0,
|
|
45591
|
+
const sourcePath = (0, import_path12.join)(sourceHome, fileName);
|
|
45592
|
+
const targetPath = (0, import_path12.join)(targetHome, fileName);
|
|
45103
45593
|
if (!fs26.existsSync(sourcePath)) continue;
|
|
45104
45594
|
try {
|
|
45105
45595
|
fs26.copyFileSync(sourcePath, targetPath);
|
|
@@ -45601,7 +46091,7 @@ var DaemonCommandRouter = class {
|
|
|
45601
46091
|
}
|
|
45602
46092
|
const { resolveWorktreePath: resolveWorktreePath2, listWorktrees: listWorktrees2, removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
45603
46093
|
const normalizePath = (value) => {
|
|
45604
|
-
const resolved = (0,
|
|
46094
|
+
const resolved = (0, import_path12.resolve)(value);
|
|
45605
46095
|
try {
|
|
45606
46096
|
return fs26.realpathSync(resolved);
|
|
45607
46097
|
} catch {
|
|
@@ -48781,6 +49271,42 @@ ${hintLines.join("\n")}` : "",
|
|
|
48781
49271
|
note: "Suggestions are heuristic scaffold only; Refinery will not execute them until saved into repo mesh/refine config."
|
|
48782
49272
|
};
|
|
48783
49273
|
}
|
|
49274
|
+
case "get_mesh_change_impact_config_schema": {
|
|
49275
|
+
return {
|
|
49276
|
+
success: true,
|
|
49277
|
+
schema: CHANGE_IMPACT_CONFIG_SCHEMA,
|
|
49278
|
+
locations: CHANGE_IMPACT_CONFIG_LOCATIONS,
|
|
49279
|
+
sourceOfTruth: "repo change-impact config",
|
|
49280
|
+
heuristicRole: "suggestions_only_not_execution_path",
|
|
49281
|
+
note: "Declarative config only \u2014 JSON/YAML are parsed but never executed. Defines which package/file changes require a daemon rebuild/restart vs. a web-only redeploy vs. nothing."
|
|
49282
|
+
};
|
|
49283
|
+
}
|
|
49284
|
+
case "validate_mesh_change_impact_config": {
|
|
49285
|
+
const workspace = typeof args?.workspace === "string" ? args.workspace : process.cwd();
|
|
49286
|
+
if (args?.config !== void 0) {
|
|
49287
|
+
const validation = validateChangeImpactConfig(args.config, "inline");
|
|
49288
|
+
return { success: validation.valid, source: "inline", sourceType: "mesh_policy", ...validation };
|
|
49289
|
+
}
|
|
49290
|
+
const loaded = loadChangeImpactConfig(workspace);
|
|
49291
|
+
if (loaded.sourceType === "repo_file") {
|
|
49292
|
+
const validation = validateChangeImpactConfig(loaded.config, loaded.source);
|
|
49293
|
+
return { success: validation.valid, ...loaded, ...validation };
|
|
49294
|
+
}
|
|
49295
|
+
return {
|
|
49296
|
+
success: false,
|
|
49297
|
+
...loaded,
|
|
49298
|
+
valid: false,
|
|
49299
|
+
errors: [loaded.error || "repo change-impact config unavailable"]
|
|
49300
|
+
};
|
|
49301
|
+
}
|
|
49302
|
+
case "suggest_mesh_change_impact_config": {
|
|
49303
|
+
const workspace = typeof args?.workspace === "string" ? args.workspace : process.cwd();
|
|
49304
|
+
return {
|
|
49305
|
+
success: true,
|
|
49306
|
+
...suggestChangeImpactConfig(workspace),
|
|
49307
|
+
note: "Suggestions are heuristic scaffold only; the draft must be reviewed and saved into repo change-impact config before it takes effect. Nothing is executed."
|
|
49308
|
+
};
|
|
49309
|
+
}
|
|
48784
49310
|
case "mesh_init": {
|
|
48785
49311
|
const workspace = typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : process.cwd();
|
|
48786
49312
|
const mesh = args?.inlineMesh || {};
|
|
@@ -49572,7 +50098,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
49572
50098
|
};
|
|
49573
50099
|
}
|
|
49574
50100
|
if (cliType === "codex-cli") {
|
|
49575
|
-
const repoMcpConfigPath = (0,
|
|
50101
|
+
const repoMcpConfigPath = (0, import_path12.join)(workspace, ".mcp.json");
|
|
49576
50102
|
if (fs26.existsSync(repoMcpConfigPath)) {
|
|
49577
50103
|
try {
|
|
49578
50104
|
const repoMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
@@ -49697,7 +50223,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
49697
50223
|
workspace
|
|
49698
50224
|
};
|
|
49699
50225
|
}
|
|
49700
|
-
const { existsSync:
|
|
50226
|
+
const { existsSync: existsSync46, readFileSync: readFileSync37, writeFileSync: writeFileSync23, copyFileSync: copyFileSync4, mkdirSync: mkdirSync21 } = await import("fs");
|
|
49701
50227
|
const { dirname: dirname17 } = await import("path");
|
|
49702
50228
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
49703
50229
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
@@ -49740,14 +50266,14 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
49740
50266
|
if (hermesManualFallback) return returnManualFallback(message);
|
|
49741
50267
|
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
49742
50268
|
}
|
|
49743
|
-
const hadExistingMcpConfig =
|
|
50269
|
+
const hadExistingMcpConfig = existsSync46(mcpConfigPath);
|
|
49744
50270
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
49745
50271
|
if (hermesBaseConfig) {
|
|
49746
50272
|
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname17(mcpConfigPath));
|
|
49747
50273
|
}
|
|
49748
50274
|
if (hadExistingMcpConfig) {
|
|
49749
50275
|
try {
|
|
49750
|
-
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
50276
|
+
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync37(mcpConfigPath, "utf-8"), configFormat);
|
|
49751
50277
|
const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
|
|
49752
50278
|
existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
|
|
49753
50279
|
copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
|
|
@@ -50246,7 +50772,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
50246
50772
|
const { deriveMeshReviewInboxItems: deriveMeshReviewInboxItems2 } = await Promise.resolve().then(() => (init_mesh_review_inbox(), mesh_review_inbox_exports));
|
|
50247
50773
|
const { readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
50248
50774
|
const { getGitDiffSummary: getGitDiffSummary2 } = await Promise.resolve().then(() => (init_git_diff(), git_diff_exports));
|
|
50249
|
-
const { existsSync:
|
|
50775
|
+
const { existsSync: existsSync46 } = await import("fs");
|
|
50250
50776
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
50251
50777
|
const mesh = meshRecord?.mesh;
|
|
50252
50778
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
@@ -50265,7 +50791,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
50265
50791
|
const derivation = deriveMeshReviewInboxItems2({ nodes: nodeStatuses, ledgerEntries });
|
|
50266
50792
|
for (const item of derivation.items) {
|
|
50267
50793
|
const workspace = item.workspace;
|
|
50268
|
-
if (!workspace || !
|
|
50794
|
+
if (!workspace || !existsSync46(workspace)) continue;
|
|
50269
50795
|
const baseRef = item.defaultBranch ? `origin/${item.defaultBranch}` : "origin/main";
|
|
50270
50796
|
try {
|
|
50271
50797
|
const diffResult = await getGitDiffSummary2(workspace, { baseRef, maxFiles: 100 });
|
|
@@ -50439,7 +50965,7 @@ var DaemonStatusReporter = class {
|
|
|
50439
50965
|
case "agent:waiting_approval":
|
|
50440
50966
|
case "agent:generating_completed":
|
|
50441
50967
|
case "agent:stopped":
|
|
50442
|
-
case "monitor:
|
|
50968
|
+
case "monitor:no_progress":
|
|
50443
50969
|
return value;
|
|
50444
50970
|
default:
|
|
50445
50971
|
return null;
|
|
@@ -50984,7 +51510,7 @@ var ProviderStreamAdapter = class {
|
|
|
50984
51510
|
}
|
|
50985
51511
|
const validated = validateReadChatResultPayload(data, `${this.agentType} readChat`);
|
|
50986
51512
|
const validatedStatus = validated.status;
|
|
50987
|
-
const streamStatus = validatedStatus === "generating" || validatedStatus === "long_generating" ? "streaming" : validatedStatus;
|
|
51513
|
+
const streamStatus = validatedStatus === "generating" || validatedStatus === "no_progress" || validatedStatus === "long_generating" ? "streaming" : validatedStatus;
|
|
50988
51514
|
const state = {
|
|
50989
51515
|
agentType: this.agentType,
|
|
50990
51516
|
agentName: this.agentName,
|
|
@@ -58903,6 +59429,8 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
58903
59429
|
AcpProviderInstance,
|
|
58904
59430
|
AgentStreamPoller,
|
|
58905
59431
|
BUILTIN_CHAT_MESSAGE_KINDS,
|
|
59432
|
+
CHANGE_IMPACT_CONFIG_LOCATIONS,
|
|
59433
|
+
CHANGE_IMPACT_CONFIG_SCHEMA,
|
|
58906
59434
|
CHAT_MESSAGE_ACTIVITY_SOURCES,
|
|
58907
59435
|
CHAT_MESSAGE_AUDIENCES,
|
|
58908
59436
|
CHAT_MESSAGE_INTERNAL_SOURCES,
|
|
@@ -59093,6 +59621,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
59093
59621
|
getSessionHostSurfaceKind,
|
|
59094
59622
|
getSessionRecoveryContext,
|
|
59095
59623
|
getWorkspaceState,
|
|
59624
|
+
globToRegExp,
|
|
59096
59625
|
handleGitCommand,
|
|
59097
59626
|
hasCdpManager,
|
|
59098
59627
|
hasPendingDependents,
|
|
@@ -59126,6 +59655,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
59126
59655
|
listMeshMissionSummaries,
|
|
59127
59656
|
listMeshes,
|
|
59128
59657
|
listWorktrees,
|
|
59658
|
+
loadChangeImpactConfig,
|
|
59129
59659
|
loadConfig,
|
|
59130
59660
|
loadMeshCoordinatorRegistry,
|
|
59131
59661
|
loadMeshRefineConfig,
|
|
@@ -59166,6 +59696,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
59166
59696
|
prepareSessionChatTailUpdate,
|
|
59167
59697
|
prepareSessionModalUpdate,
|
|
59168
59698
|
probeCdpPort,
|
|
59699
|
+
pruneStaleDirectDispatches,
|
|
59169
59700
|
queuePendingMeshCoordinatorEvent,
|
|
59170
59701
|
readAntigravityCliSession,
|
|
59171
59702
|
readCachedInlineMeshActiveSessionDetails,
|
|
@@ -59219,6 +59750,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
59219
59750
|
spawnDetachedDaemonUpgradeHelper,
|
|
59220
59751
|
startDaemonDevSupport,
|
|
59221
59752
|
startLocalIpcServer,
|
|
59753
|
+
suggestChangeImpactConfig,
|
|
59222
59754
|
suggestMeshRefineConfig,
|
|
59223
59755
|
summarizeGitStatus,
|
|
59224
59756
|
summarizeMeshAsyncRefineJobs,
|
|
@@ -59235,6 +59767,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
59235
59767
|
updateTaskStatus,
|
|
59236
59768
|
upsertMeshMission,
|
|
59237
59769
|
upsertSavedProviderSession,
|
|
59770
|
+
validateChangeImpactConfig,
|
|
59238
59771
|
validateCliProviderManifest,
|
|
59239
59772
|
validateFsmSpec,
|
|
59240
59773
|
validateMeshRefineConfig,
|