@adhdev/daemon-core 0.9.82-rc.328 → 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.js +647 -281
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +598 -238
- package/dist/index.mjs.map +1 -1
- 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/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/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.mjs
CHANGED
|
@@ -308,10 +308,10 @@ function readInjected(value) {
|
|
|
308
308
|
}
|
|
309
309
|
function getDaemonBuildInfo() {
|
|
310
310
|
if (cached) return cached;
|
|
311
|
-
const commit = readInjected(true ? "
|
|
312
|
-
const commitShort = readInjected(true ? "
|
|
313
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
314
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
311
|
+
const commit = readInjected(true ? "9277ba79593a0feae0e17de0204856825a199ebe" : void 0) ?? "unknown";
|
|
312
|
+
const commitShort = readInjected(true ? "9277ba79" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
313
|
+
const version = readInjected(true ? "0.9.82-rc.329" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
314
|
+
const builtAt = readInjected(true ? "2026-06-19T15:56:44.269Z" : void 0);
|
|
315
315
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
316
316
|
return cached;
|
|
317
317
|
}
|
|
@@ -322,6 +322,247 @@ var init_build_info = __esm({
|
|
|
322
322
|
}
|
|
323
323
|
});
|
|
324
324
|
|
|
325
|
+
// src/git/change-impact-config.ts
|
|
326
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
327
|
+
import { join } from "path";
|
|
328
|
+
import * as yaml from "js-yaml";
|
|
329
|
+
function isRecord(value) {
|
|
330
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
331
|
+
}
|
|
332
|
+
function isStringArray(value) {
|
|
333
|
+
return Array.isArray(value) && value.every((v) => typeof v === "string" && v.length > 0);
|
|
334
|
+
}
|
|
335
|
+
function validateTarget(value, key, errors) {
|
|
336
|
+
if (!isRecord(value)) {
|
|
337
|
+
errors.push(`impactTargets.${key} must be an object`);
|
|
338
|
+
return void 0;
|
|
339
|
+
}
|
|
340
|
+
const { recommendedCommand } = value;
|
|
341
|
+
if (typeof recommendedCommand !== "string" || !recommendedCommand.length) {
|
|
342
|
+
errors.push(`impactTargets.${key}.recommendedCommand must be a non-empty string`);
|
|
343
|
+
return void 0;
|
|
344
|
+
}
|
|
345
|
+
for (const k of Object.keys(value)) {
|
|
346
|
+
if (k !== "recommendedCommand") errors.push(`impactTargets.${key}.${k} is not a recognized field (only recommendedCommand)`);
|
|
347
|
+
}
|
|
348
|
+
return { recommendedCommand };
|
|
349
|
+
}
|
|
350
|
+
function validateChangeImpactConfig(raw, source = "inline") {
|
|
351
|
+
const errors = [];
|
|
352
|
+
if (!isRecord(raw)) {
|
|
353
|
+
return { valid: false, errors: [`${source}: config must be an object`] };
|
|
354
|
+
}
|
|
355
|
+
const config = {};
|
|
356
|
+
if (raw.daemonRuntimePackages !== void 0) {
|
|
357
|
+
if (isStringArray(raw.daemonRuntimePackages)) config.daemonRuntimePackages = [...raw.daemonRuntimePackages];
|
|
358
|
+
else errors.push("daemonRuntimePackages must be an array of non-empty strings");
|
|
359
|
+
}
|
|
360
|
+
if (raw.webOnlyPackages !== void 0) {
|
|
361
|
+
if (isStringArray(raw.webOnlyPackages)) config.webOnlyPackages = [...raw.webOnlyPackages];
|
|
362
|
+
else errors.push("webOnlyPackages must be an array of non-empty strings");
|
|
363
|
+
}
|
|
364
|
+
if (raw.nonRuntimeRootFilePatterns !== void 0) {
|
|
365
|
+
if (isStringArray(raw.nonRuntimeRootFilePatterns)) config.nonRuntimeRootFilePatterns = [...raw.nonRuntimeRootFilePatterns];
|
|
366
|
+
else errors.push("nonRuntimeRootFilePatterns must be an array of non-empty strings");
|
|
367
|
+
}
|
|
368
|
+
if (raw.impactTargets !== void 0) {
|
|
369
|
+
if (!isRecord(raw.impactTargets)) {
|
|
370
|
+
errors.push("impactTargets must be an object");
|
|
371
|
+
} else {
|
|
372
|
+
const targets = {};
|
|
373
|
+
for (const key of Object.keys(raw.impactTargets)) {
|
|
374
|
+
if (key !== "daemon" && key !== "web" && key !== "none") {
|
|
375
|
+
errors.push(`impactTargets.${key} is not a recognized impact kind (daemon|web|none)`);
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
const target = validateTarget(raw.impactTargets[key], key, errors);
|
|
379
|
+
if (target) targets[key] = target;
|
|
380
|
+
}
|
|
381
|
+
if (Object.keys(targets).length) config.impactTargets = targets;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
for (const key of Object.keys(raw)) {
|
|
385
|
+
if (!["daemonRuntimePackages", "webOnlyPackages", "nonRuntimeRootFilePatterns", "impactTargets"].includes(key)) {
|
|
386
|
+
errors.push(`unknown config key '${key}'`);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return { valid: errors.length === 0, errors, config: errors.length === 0 ? config : void 0 };
|
|
390
|
+
}
|
|
391
|
+
function parseConfigText(path42, text) {
|
|
392
|
+
if (/\.json$/i.test(path42)) return JSON.parse(text);
|
|
393
|
+
return yaml.load(text);
|
|
394
|
+
}
|
|
395
|
+
function loadChangeImpactConfig(repoRoot) {
|
|
396
|
+
for (const relative5 of CHANGE_IMPACT_CONFIG_LOCATIONS) {
|
|
397
|
+
const configPath = join(repoRoot, relative5);
|
|
398
|
+
if (!existsSync(configPath)) continue;
|
|
399
|
+
try {
|
|
400
|
+
const text = readFileSync(configPath, "utf-8");
|
|
401
|
+
let mtimeMs = 0;
|
|
402
|
+
try {
|
|
403
|
+
mtimeMs = statSync(configPath).mtimeMs;
|
|
404
|
+
} catch {
|
|
405
|
+
mtimeMs = text.length;
|
|
406
|
+
}
|
|
407
|
+
const parsed = parseConfigText(configPath, text);
|
|
408
|
+
const validation = validateChangeImpactConfig(parsed, relative5);
|
|
409
|
+
if (!validation.valid) {
|
|
410
|
+
return {
|
|
411
|
+
source: relative5,
|
|
412
|
+
sourceType: "invalid",
|
|
413
|
+
path: configPath,
|
|
414
|
+
error: validation.errors.join("; "),
|
|
415
|
+
sourceKey: `invalid:${configPath}:${mtimeMs}`
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
return {
|
|
419
|
+
config: validation.config,
|
|
420
|
+
source: relative5,
|
|
421
|
+
sourceType: "repo_file",
|
|
422
|
+
path: configPath,
|
|
423
|
+
sourceKey: `file:${configPath}:${mtimeMs}`
|
|
424
|
+
};
|
|
425
|
+
} catch (error) {
|
|
426
|
+
return {
|
|
427
|
+
source: relative5,
|
|
428
|
+
sourceType: "invalid",
|
|
429
|
+
path: configPath,
|
|
430
|
+
error: error?.message || String(error),
|
|
431
|
+
sourceKey: `error:${configPath}`
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return {
|
|
436
|
+
source: "unavailable",
|
|
437
|
+
sourceType: "unavailable",
|
|
438
|
+
error: `No change-impact config found. Checked: ${CHANGE_IMPACT_CONFIG_LOCATIONS.join(", ")}`,
|
|
439
|
+
sourceKey: "unavailable"
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
function globToRegExp(pattern) {
|
|
443
|
+
let out = "";
|
|
444
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
445
|
+
const ch = pattern[i];
|
|
446
|
+
if (ch === "*") {
|
|
447
|
+
if (pattern[i + 1] === "*") {
|
|
448
|
+
out += ".*";
|
|
449
|
+
i++;
|
|
450
|
+
if (pattern[i + 1] === "/") i++;
|
|
451
|
+
} else {
|
|
452
|
+
out += "[^/]*";
|
|
453
|
+
}
|
|
454
|
+
} else if (ch === "?") {
|
|
455
|
+
out += "[^/]";
|
|
456
|
+
} else if (".+^${}()|[]\\".includes(ch)) {
|
|
457
|
+
out += "\\" + ch;
|
|
458
|
+
} else {
|
|
459
|
+
out += ch;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return new RegExp(`^${out}$`);
|
|
463
|
+
}
|
|
464
|
+
function listPackageDirs(packagesRoot) {
|
|
465
|
+
try {
|
|
466
|
+
return readdirSync(packagesRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
|
|
467
|
+
} catch {
|
|
468
|
+
return [];
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
function suggestChangeImpactConfig(repoRoot) {
|
|
472
|
+
const notes = [];
|
|
473
|
+
const daemon = /* @__PURE__ */ new Set();
|
|
474
|
+
const web = /* @__PURE__ */ new Set();
|
|
475
|
+
const unclassified = [];
|
|
476
|
+
const roots = ["packages", join("oss", "packages")];
|
|
477
|
+
for (const rel of roots) {
|
|
478
|
+
const packagesRoot = join(repoRoot, rel);
|
|
479
|
+
if (!existsSync(packagesRoot)) continue;
|
|
480
|
+
for (const name of listPackageDirs(packagesRoot)) {
|
|
481
|
+
if (/(^web[-.]|[-.]web$)/i.test(name) || /dashboard|frontend|ui$/i.test(name)) {
|
|
482
|
+
web.add(name);
|
|
483
|
+
} else {
|
|
484
|
+
daemon.add(name);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
const daemonRuntimePackages = [...daemon].sort();
|
|
489
|
+
const webOnlyPackages = [...web].sort();
|
|
490
|
+
if (!daemonRuntimePackages.length && !webOnlyPackages.length) {
|
|
491
|
+
notes.push("No packages/ or oss/packages/ directories found \u2014 defaulting to an empty draft you should fill in by hand.");
|
|
492
|
+
} else {
|
|
493
|
+
if (daemonRuntimePackages.length) notes.push(`Classified ${daemonRuntimePackages.length} package(s) as daemon-runtime (change \u2192 rebuild/redeploy + restart).`);
|
|
494
|
+
if (webOnlyPackages.length) notes.push(`Classified ${webOnlyPackages.length} web-* package(s) as web-only (change \u2192 web redeploy, no daemon restart).`);
|
|
495
|
+
notes.push("Heuristic only: confirm each package actually matches its bucket before saving.");
|
|
496
|
+
}
|
|
497
|
+
const nonRuntimeRootFilePatterns = [
|
|
498
|
+
"*.md",
|
|
499
|
+
"docs/**",
|
|
500
|
+
"LICENSE",
|
|
501
|
+
"LICENSE.*",
|
|
502
|
+
".gitignore"
|
|
503
|
+
];
|
|
504
|
+
notes.push("nonRuntimeRootFilePatterns lists root files that demonstrably cannot change daemon runtime behavior; extend with your repo markers.");
|
|
505
|
+
const suggestedConfig = {
|
|
506
|
+
...daemonRuntimePackages.length ? { daemonRuntimePackages } : {},
|
|
507
|
+
...webOnlyPackages.length ? { webOnlyPackages } : {},
|
|
508
|
+
nonRuntimeRootFilePatterns,
|
|
509
|
+
impactTargets: {
|
|
510
|
+
daemon: { recommendedCommand: "rebuild + redeploy the daemon, then restart it" },
|
|
511
|
+
web: { recommendedCommand: "redeploy the web app (no daemon restart required)" },
|
|
512
|
+
none: { recommendedCommand: "no action required" }
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
return {
|
|
516
|
+
suggestedConfig,
|
|
517
|
+
notes,
|
|
518
|
+
discoveredPackages: { daemon: daemonRuntimePackages, web: webOnlyPackages, unclassified }
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
var CHANGE_IMPACT_CONFIG_LOCATIONS, CHANGE_IMPACT_CONFIG_SCHEMA;
|
|
522
|
+
var init_change_impact_config = __esm({
|
|
523
|
+
"src/git/change-impact-config.ts"() {
|
|
524
|
+
"use strict";
|
|
525
|
+
CHANGE_IMPACT_CONFIG_LOCATIONS = [
|
|
526
|
+
".adhdev/change-impact.json",
|
|
527
|
+
".adhdev/change-impact.yaml",
|
|
528
|
+
".adhdev/change-impact.yml",
|
|
529
|
+
".adhdev/repo-mesh-change-impact.json",
|
|
530
|
+
".adhdev/repo-mesh-change-impact.yaml",
|
|
531
|
+
".adhdev/repo-mesh-change-impact.yml"
|
|
532
|
+
];
|
|
533
|
+
CHANGE_IMPACT_CONFIG_SCHEMA = {
|
|
534
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
535
|
+
title: "ADHDev Change Impact Config",
|
|
536
|
+
type: "object",
|
|
537
|
+
additionalProperties: false,
|
|
538
|
+
properties: {
|
|
539
|
+
daemonRuntimePackages: { type: "array", items: { type: "string", minLength: 1 } },
|
|
540
|
+
webOnlyPackages: { type: "array", items: { type: "string", minLength: 1 } },
|
|
541
|
+
nonRuntimeRootFilePatterns: { type: "array", items: { type: "string", minLength: 1 } },
|
|
542
|
+
impactTargets: {
|
|
543
|
+
type: "object",
|
|
544
|
+
additionalProperties: false,
|
|
545
|
+
properties: {
|
|
546
|
+
daemon: { $ref: "#/$defs/target" },
|
|
547
|
+
web: { $ref: "#/$defs/target" },
|
|
548
|
+
none: { $ref: "#/$defs/target" }
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
$defs: {
|
|
553
|
+
target: {
|
|
554
|
+
type: "object",
|
|
555
|
+
additionalProperties: false,
|
|
556
|
+
required: ["recommendedCommand"],
|
|
557
|
+
properties: {
|
|
558
|
+
recommendedCommand: { type: "string", minLength: 1 }
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
|
|
325
566
|
// src/git/git-status.ts
|
|
326
567
|
function isTransientGitFailure(error) {
|
|
327
568
|
return error.reason === "timeout" || error.reason === "git_command_failed";
|
|
@@ -397,16 +638,34 @@ async function collectGitRepoStatus(repo, includeSubmodules, lastCheckedAt, opti
|
|
|
397
638
|
...daemonBuildBehind ? { daemonBuildBehind } : {}
|
|
398
639
|
};
|
|
399
640
|
}
|
|
400
|
-
function
|
|
641
|
+
function resolveChangeImpactPolicy(config) {
|
|
642
|
+
const daemonRuntimePackages = new Set(
|
|
643
|
+
config?.daemonRuntimePackages && config.daemonRuntimePackages.length ? config.daemonRuntimePackages : DEFAULT_DAEMON_RUNTIME_PACKAGES
|
|
644
|
+
);
|
|
645
|
+
const webOnlyPackages = new Set(
|
|
646
|
+
config?.webOnlyPackages && config.webOnlyPackages.length ? config.webOnlyPackages : DEFAULT_WEB_ONLY_PACKAGES
|
|
647
|
+
);
|
|
648
|
+
const nonRuntimeRootFilePatterns = (config?.nonRuntimeRootFilePatterns || []).map(globToRegExp);
|
|
649
|
+
const impactTargets = {
|
|
650
|
+
daemon: config?.impactTargets?.daemon ?? DEFAULT_IMPACT_TARGETS.daemon,
|
|
651
|
+
web: config?.impactTargets?.web ?? DEFAULT_IMPACT_TARGETS.web,
|
|
652
|
+
none: config?.impactTargets?.none ?? DEFAULT_IMPACT_TARGETS.none
|
|
653
|
+
};
|
|
654
|
+
return { daemonRuntimePackages, webOnlyPackages, nonRuntimeRootFilePatterns, impactTargets };
|
|
655
|
+
}
|
|
656
|
+
function isNonRuntimeRootFile(file, policy) {
|
|
401
657
|
const base = file.slice(file.lastIndexOf("/") + 1);
|
|
402
658
|
if (/^\.(?:verify|marker|converge|ff-verify|patch-equiv|live-verify)\b/i.test(base)) return true;
|
|
403
659
|
if (/(?:^|\/)docs\//i.test(file)) return true;
|
|
404
660
|
if (/^(?:README|CHANGELOG|LICENSE|NOTICE|AUTHORS|CONTRIBUTING|CODEOWNERS)(?:\.[A-Za-z0-9]+)?$/i.test(base)) {
|
|
405
661
|
return true;
|
|
406
662
|
}
|
|
663
|
+
for (const re of policy.nonRuntimeRootFilePatterns) {
|
|
664
|
+
if (re.test(file)) return true;
|
|
665
|
+
}
|
|
407
666
|
return false;
|
|
408
667
|
}
|
|
409
|
-
async function classifyDaemonBuildChange(repoPath, buildCommit, options) {
|
|
668
|
+
async function classifyDaemonBuildChange(repoPath, buildCommit, options, policy) {
|
|
410
669
|
try {
|
|
411
670
|
const diff = await runGit(repoPath, ["diff", "--name-only", `${buildCommit}..HEAD`], options);
|
|
412
671
|
const files = diff.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
@@ -418,21 +677,47 @@ async function classifyDaemonBuildChange(repoPath, buildCommit, options) {
|
|
|
418
677
|
for (const file of files) {
|
|
419
678
|
const match = file.match(/(?:^|\/)packages\/([^/]+)\//);
|
|
420
679
|
if (!match) {
|
|
421
|
-
if (!isNonRuntimeRootFile(file)) sawRuntimeAmbiguousNonPackage = true;
|
|
680
|
+
if (!isNonRuntimeRootFile(file, policy)) sawRuntimeAmbiguousNonPackage = true;
|
|
422
681
|
continue;
|
|
423
682
|
}
|
|
424
683
|
pkgs.add(match[1]);
|
|
425
684
|
}
|
|
426
685
|
const affectedPackages = [...pkgs].sort();
|
|
427
|
-
const allBenign = !sawRuntimeAmbiguousNonPackage && affectedPackages.every((p) =>
|
|
686
|
+
const allBenign = !sawRuntimeAmbiguousNonPackage && affectedPackages.every((p) => policy.webOnlyPackages.has(p) && !policy.daemonRuntimePackages.has(p));
|
|
428
687
|
return { isDaemonAffecting: !allBenign, affectedPackages };
|
|
429
688
|
} catch {
|
|
430
689
|
return { isDaemonAffecting: true, affectedPackages: [] };
|
|
431
690
|
}
|
|
432
691
|
}
|
|
692
|
+
function resolveChangeImpactConfigForRepo(repoRoot, options) {
|
|
693
|
+
if (options.changeImpactConfig === null) {
|
|
694
|
+
return { config: null, sourceKey: "forced-default" };
|
|
695
|
+
}
|
|
696
|
+
if (options.changeImpactConfig !== void 0) {
|
|
697
|
+
let key = "injected";
|
|
698
|
+
try {
|
|
699
|
+
key = `injected:${JSON.stringify(options.changeImpactConfig)}`;
|
|
700
|
+
} catch {
|
|
701
|
+
}
|
|
702
|
+
return { config: options.changeImpactConfig, sourceKey: key };
|
|
703
|
+
}
|
|
704
|
+
if (!repoRoot) {
|
|
705
|
+
return { config: null, sourceKey: "no-repo-root" };
|
|
706
|
+
}
|
|
707
|
+
const loaded = loadChangeImpactConfig(repoRoot);
|
|
708
|
+
const cached2 = changeImpactConfigCache.get(repoRoot);
|
|
709
|
+
if (cached2 && cached2.sourceKey === loaded.sourceKey) {
|
|
710
|
+
return { config: cached2.config, sourceKey: loaded.sourceKey };
|
|
711
|
+
}
|
|
712
|
+
const config = loaded.sourceType === "repo_file" ? loaded.config ?? null : null;
|
|
713
|
+
changeImpactConfigCache.set(repoRoot, { sourceKey: loaded.sourceKey, config });
|
|
714
|
+
return { config, sourceKey: loaded.sourceKey };
|
|
715
|
+
}
|
|
433
716
|
async function detectDaemonBuildBehind(repo, submodules, options) {
|
|
434
717
|
const build = options.daemonBuildInfo ?? getDaemonBuildInfo();
|
|
435
718
|
if (!build.commit || build.commit === "unknown") return void 0;
|
|
719
|
+
const { config, sourceKey: configKey } = resolveChangeImpactConfigForRepo(repo.repoRoot, options);
|
|
720
|
+
const policy = resolveChangeImpactPolicy(config);
|
|
436
721
|
const scopes = [
|
|
437
722
|
{ scope: "root", repoPath: repo.repoRoot || repo.workspace }
|
|
438
723
|
];
|
|
@@ -446,11 +731,15 @@ async function detectDaemonBuildBehind(repo, submodules, options) {
|
|
|
446
731
|
const head = headResult.stdout.trim();
|
|
447
732
|
if (!head || head === build.commit) continue;
|
|
448
733
|
await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
options
|
|
453
|
-
|
|
734
|
+
const evalKey = `${repoPath}\0${build.commit}\0${head}\0${configKey}`;
|
|
735
|
+
let evaluated = changeImpactEvalCache.get(evalKey);
|
|
736
|
+
if (!evaluated) {
|
|
737
|
+
evaluated = await classifyDaemonBuildChange(repoPath, build.commit, options, policy);
|
|
738
|
+
changeImpactEvalCache.set(evalKey, evaluated);
|
|
739
|
+
}
|
|
740
|
+
const { isDaemonAffecting, affectedPackages } = evaluated;
|
|
741
|
+
const kind = isDaemonAffecting ? "daemon" : affectedPackages.length > 0 ? "web" : "none";
|
|
742
|
+
const target = policy.impactTargets[kind];
|
|
454
743
|
const scopeLabel = scope === "root" ? "workspace" : scope;
|
|
455
744
|
const benignDetail = affectedPackages.length > 0 ? `only web packages changed (${affectedPackages.join(", ")})` : "only non-runtime files changed (markers/docs)";
|
|
456
745
|
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.`;
|
|
@@ -461,6 +750,8 @@ async function detectDaemonBuildBehind(repo, submodules, options) {
|
|
|
461
750
|
scope,
|
|
462
751
|
isDaemonAffecting,
|
|
463
752
|
...affectedPackages && affectedPackages.length > 0 ? { affectedPackages } : {},
|
|
753
|
+
recommendedAction: kind,
|
|
754
|
+
recommendedCommand: target.recommendedCommand,
|
|
464
755
|
warning
|
|
465
756
|
};
|
|
466
757
|
} catch {
|
|
@@ -724,14 +1015,17 @@ async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
|
|
|
724
1015
|
submodule.error = formatGitError(error);
|
|
725
1016
|
}
|
|
726
1017
|
}
|
|
727
|
-
var lastKnownGoodStatus,
|
|
1018
|
+
var lastKnownGoodStatus, changeImpactEvalCache, changeImpactConfigCache, DEFAULT_DAEMON_RUNTIME_PACKAGES, DEFAULT_WEB_ONLY_PACKAGES, DEFAULT_IMPACT_TARGETS;
|
|
728
1019
|
var init_git_status = __esm({
|
|
729
1020
|
"src/git/git-status.ts"() {
|
|
730
1021
|
"use strict";
|
|
731
1022
|
init_git_executor();
|
|
732
1023
|
init_build_info();
|
|
1024
|
+
init_change_impact_config();
|
|
733
1025
|
lastKnownGoodStatus = /* @__PURE__ */ new Map();
|
|
734
|
-
|
|
1026
|
+
changeImpactEvalCache = /* @__PURE__ */ new Map();
|
|
1027
|
+
changeImpactConfigCache = /* @__PURE__ */ new Map();
|
|
1028
|
+
DEFAULT_DAEMON_RUNTIME_PACKAGES = [
|
|
735
1029
|
"daemon-core",
|
|
736
1030
|
"daemon-standalone",
|
|
737
1031
|
"session-host-core",
|
|
@@ -741,13 +1035,24 @@ var init_git_status = __esm({
|
|
|
741
1035
|
"terminal-mux-cli",
|
|
742
1036
|
"ghostty-vt-node",
|
|
743
1037
|
"mcp-server"
|
|
744
|
-
]
|
|
745
|
-
|
|
1038
|
+
];
|
|
1039
|
+
DEFAULT_WEB_ONLY_PACKAGES = [
|
|
746
1040
|
"web-core",
|
|
747
1041
|
"web-standalone",
|
|
748
1042
|
"web-devconsole",
|
|
749
1043
|
"terminal-render-web"
|
|
750
|
-
]
|
|
1044
|
+
];
|
|
1045
|
+
DEFAULT_IMPACT_TARGETS = {
|
|
1046
|
+
daemon: {
|
|
1047
|
+
recommendedCommand: "Redeploy + restart the daemon (a local dist rebuild alone does not update a cloud daemon)."
|
|
1048
|
+
},
|
|
1049
|
+
web: {
|
|
1050
|
+
recommendedCommand: "Redeploy the web app (no daemon restart required)."
|
|
1051
|
+
},
|
|
1052
|
+
none: {
|
|
1053
|
+
recommendedCommand: "No action required."
|
|
1054
|
+
}
|
|
1055
|
+
};
|
|
751
1056
|
}
|
|
752
1057
|
});
|
|
753
1058
|
|
|
@@ -1035,7 +1340,7 @@ __export(git_worktree_exports, {
|
|
|
1035
1340
|
});
|
|
1036
1341
|
import * as path4 from "path";
|
|
1037
1342
|
import { mkdir } from "fs/promises";
|
|
1038
|
-
import { existsSync } from "fs";
|
|
1343
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1039
1344
|
import { execFile as execFile2 } from "child_process";
|
|
1040
1345
|
import { promisify as promisify2 } from "util";
|
|
1041
1346
|
function resolveWorktreePath(repoRoot, meshName, branch) {
|
|
@@ -1047,7 +1352,7 @@ function resolveWorktreePath(repoRoot, meshName, branch) {
|
|
|
1047
1352
|
async function createWorktree(opts) {
|
|
1048
1353
|
const { repoRoot, branch, baseBranch, meshName } = opts;
|
|
1049
1354
|
const targetDir = opts.targetDir || resolveWorktreePath(repoRoot, meshName, branch);
|
|
1050
|
-
if (
|
|
1355
|
+
if (existsSync2(targetDir)) {
|
|
1051
1356
|
throw new Error(`Worktree target directory already exists: ${targetDir}`);
|
|
1052
1357
|
}
|
|
1053
1358
|
await mkdir(path4.dirname(targetDir), { recursive: true });
|
|
@@ -1066,7 +1371,7 @@ async function createWorktree(opts) {
|
|
|
1066
1371
|
} catch (error) {
|
|
1067
1372
|
const stderr = typeof error.stderr === "string" ? error.stderr : "";
|
|
1068
1373
|
if (/already exists/i.test(stderr)) {
|
|
1069
|
-
if (
|
|
1374
|
+
if (existsSync2(targetDir)) {
|
|
1070
1375
|
throw new Error(`Worktree target directory was created concurrently: ${targetDir}`);
|
|
1071
1376
|
}
|
|
1072
1377
|
throw new Error(`Branch '${branch}' already exists or is checked out in another worktree`);
|
|
@@ -1080,7 +1385,7 @@ async function createWorktree(opts) {
|
|
|
1080
1385
|
};
|
|
1081
1386
|
}
|
|
1082
1387
|
async function removeWorktree(repoRoot, worktreePath, opts = {}) {
|
|
1083
|
-
if (!
|
|
1388
|
+
if (!existsSync2(worktreePath)) {
|
|
1084
1389
|
await pruneWorktrees(repoRoot);
|
|
1085
1390
|
return { success: true, removedPath: worktreePath };
|
|
1086
1391
|
}
|
|
@@ -1214,8 +1519,8 @@ __export(config_exports, {
|
|
|
1214
1519
|
updateConfig: () => updateConfig
|
|
1215
1520
|
});
|
|
1216
1521
|
import { homedir } from "os";
|
|
1217
|
-
import { join as
|
|
1218
|
-
import { existsSync as
|
|
1522
|
+
import { join as join3 } from "path";
|
|
1523
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync, chmodSync } from "fs";
|
|
1219
1524
|
import { randomUUID } from "crypto";
|
|
1220
1525
|
function resolveProviderSourceMode(providerSourceMode, legacyDisableUpstream) {
|
|
1221
1526
|
if (providerSourceMode === "normal" || providerSourceMode === "no-upstream") {
|
|
@@ -1310,25 +1615,25 @@ function ensureMachineId(config) {
|
|
|
1310
1615
|
}
|
|
1311
1616
|
function getConfigDir() {
|
|
1312
1617
|
const override = process.env.ADHDEV_CONFIG_DIR;
|
|
1313
|
-
const dir = override && override.trim() ? override.trim() :
|
|
1314
|
-
if (!
|
|
1618
|
+
const dir = override && override.trim() ? override.trim() : join3(homedir(), ".adhdev");
|
|
1619
|
+
if (!existsSync3(dir)) {
|
|
1315
1620
|
mkdirSync(dir, { recursive: true });
|
|
1316
1621
|
}
|
|
1317
1622
|
return dir;
|
|
1318
1623
|
}
|
|
1319
1624
|
function getDaemonDataDir() {
|
|
1320
|
-
const dir =
|
|
1321
|
-
if (!
|
|
1625
|
+
const dir = join3(getConfigDir(), "daemon");
|
|
1626
|
+
if (!existsSync3(dir)) {
|
|
1322
1627
|
mkdirSync(dir, { recursive: true });
|
|
1323
1628
|
}
|
|
1324
1629
|
return dir;
|
|
1325
1630
|
}
|
|
1326
1631
|
function getConfigPath() {
|
|
1327
|
-
return
|
|
1632
|
+
return join3(getConfigDir(), "config.json");
|
|
1328
1633
|
}
|
|
1329
1634
|
function migrateStateToStateFile(raw) {
|
|
1330
|
-
const statePath =
|
|
1331
|
-
if (
|
|
1635
|
+
const statePath = join3(getConfigDir(), "state.json");
|
|
1636
|
+
if (existsSync3(statePath)) return;
|
|
1332
1637
|
const recentActivity = Array.isArray(raw.recentActivity) ? raw.recentActivity : [];
|
|
1333
1638
|
const savedProviderSessions = Array.isArray(raw.savedProviderSessions) ? raw.savedProviderSessions : [];
|
|
1334
1639
|
const legacySessionReads = isPlainObject(raw.recentSessionReads) ? raw.recentSessionReads : {};
|
|
@@ -1352,7 +1657,7 @@ function migrateStateToStateFile(raw) {
|
|
|
1352
1657
|
}
|
|
1353
1658
|
function loadConfig() {
|
|
1354
1659
|
const configPath = getConfigPath();
|
|
1355
|
-
if (!
|
|
1660
|
+
if (!existsSync3(configPath)) {
|
|
1356
1661
|
const initialized = ensureMachineId({ ...DEFAULT_CONFIG });
|
|
1357
1662
|
try {
|
|
1358
1663
|
saveConfig(initialized.config);
|
|
@@ -1361,7 +1666,7 @@ function loadConfig() {
|
|
|
1361
1666
|
return initialized.config;
|
|
1362
1667
|
}
|
|
1363
1668
|
try {
|
|
1364
|
-
const raw =
|
|
1669
|
+
const raw = readFileSync2(configPath, "utf-8");
|
|
1365
1670
|
const parsed = JSON.parse(raw);
|
|
1366
1671
|
migrateStateToStateFile(parsed);
|
|
1367
1672
|
const normalizedInput = normalizeConfig(parsed);
|
|
@@ -1383,7 +1688,7 @@ function saveConfig(config) {
|
|
|
1383
1688
|
const configPath = getConfigPath();
|
|
1384
1689
|
const dir = getConfigDir();
|
|
1385
1690
|
const normalized = normalizeConfig(config);
|
|
1386
|
-
if (!
|
|
1691
|
+
if (!existsSync3(dir)) {
|
|
1387
1692
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
1388
1693
|
}
|
|
1389
1694
|
writeFileSync(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
@@ -1535,17 +1840,17 @@ __export(mesh_config_exports, {
|
|
|
1535
1840
|
updateMesh: () => updateMesh,
|
|
1536
1841
|
updateNode: () => updateNode
|
|
1537
1842
|
});
|
|
1538
|
-
import { existsSync as
|
|
1539
|
-
import { join as
|
|
1843
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
1844
|
+
import { join as join5 } from "path";
|
|
1540
1845
|
import { createHash, randomBytes, randomUUID as randomUUID3 } from "crypto";
|
|
1541
1846
|
function getMeshConfigPath() {
|
|
1542
|
-
return
|
|
1847
|
+
return join5(getConfigDir(), "meshes.json");
|
|
1543
1848
|
}
|
|
1544
1849
|
function loadMeshConfig() {
|
|
1545
1850
|
const path42 = getMeshConfigPath();
|
|
1546
|
-
if (!
|
|
1851
|
+
if (!existsSync5(path42)) return { meshes: [] };
|
|
1547
1852
|
try {
|
|
1548
|
-
const raw = JSON.parse(
|
|
1853
|
+
const raw = JSON.parse(readFileSync3(path42, "utf-8"));
|
|
1549
1854
|
if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
|
|
1550
1855
|
const config = raw;
|
|
1551
1856
|
const migrated = migrateLoadedMeshConfig(config);
|
|
@@ -2248,8 +2553,8 @@ __export(mesh_ledger_exports, {
|
|
|
2248
2553
|
readLedgerSlice: () => readLedgerSlice,
|
|
2249
2554
|
readLedgerSliceFromStore: () => readLedgerSliceFromStore
|
|
2250
2555
|
});
|
|
2251
|
-
import { appendFileSync, existsSync as
|
|
2252
|
-
import { join as
|
|
2556
|
+
import { appendFileSync, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync5, statSync as statSync3, renameSync, writeFileSync as writeFileSync3 } from "fs";
|
|
2557
|
+
import { join as join7 } from "path";
|
|
2253
2558
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
2254
2559
|
import { EventEmitter } from "events";
|
|
2255
2560
|
function isIntentionalCleanupStopEntry(entry) {
|
|
@@ -2258,35 +2563,35 @@ function isIntentionalCleanupStopEntry(entry) {
|
|
|
2258
2563
|
return payload.intentional === true && (payload.reason === "operator_cleanup" || payload.intentionalStopReason === "operator_cleanup" || payload.source === "mesh_cleanup_sessions" || payload.source === "mesh_remove_node");
|
|
2259
2564
|
}
|
|
2260
2565
|
function getLedgerDir() {
|
|
2261
|
-
const dir =
|
|
2262
|
-
if (!
|
|
2566
|
+
const dir = join7(getConfigDir(), LEDGER_DIR_NAME);
|
|
2567
|
+
if (!existsSync6(dir)) {
|
|
2263
2568
|
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
2264
2569
|
}
|
|
2265
2570
|
return dir;
|
|
2266
2571
|
}
|
|
2267
2572
|
function getLedgerPath(meshId) {
|
|
2268
2573
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2269
|
-
return
|
|
2574
|
+
return join7(getLedgerDir(), `${safe}.jsonl`);
|
|
2270
2575
|
}
|
|
2271
2576
|
function getRotatedPath(meshId, index) {
|
|
2272
2577
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2273
|
-
return
|
|
2578
|
+
return join7(getLedgerDir(), `${safe}.${index}.jsonl`);
|
|
2274
2579
|
}
|
|
2275
2580
|
function getArchivePath(meshId) {
|
|
2276
2581
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2277
|
-
return
|
|
2582
|
+
return join7(getLedgerDir(), `${safe}.archive.jsonl`);
|
|
2278
2583
|
}
|
|
2279
2584
|
function getRotatedArchivePath(meshId, index) {
|
|
2280
2585
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2281
|
-
return
|
|
2586
|
+
return join7(getLedgerDir(), `${safe}.archive.${index}.jsonl`);
|
|
2282
2587
|
}
|
|
2283
2588
|
function getArchivedCountsPath(meshId) {
|
|
2284
2589
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2285
|
-
return
|
|
2590
|
+
return join7(getLedgerDir(), `${safe}.archived-counts.json`);
|
|
2286
2591
|
}
|
|
2287
2592
|
function rotateArchiveFile(meshId, archivePath) {
|
|
2288
2593
|
let index = 1;
|
|
2289
|
-
while (
|
|
2594
|
+
while (existsSync6(getRotatedArchivePath(meshId, index))) {
|
|
2290
2595
|
index++;
|
|
2291
2596
|
if (index > 5) break;
|
|
2292
2597
|
}
|
|
@@ -2300,9 +2605,9 @@ function rotateArchiveFile(meshId, archivePath) {
|
|
|
2300
2605
|
}
|
|
2301
2606
|
function readArchivedCounts(meshId) {
|
|
2302
2607
|
const path42 = getArchivedCountsPath(meshId);
|
|
2303
|
-
if (!
|
|
2608
|
+
if (!existsSync6(path42)) return { taskCompleted: 0, taskFailed: 0, taskStalled: 0, recoveryAttempted: 0, totalArchived: 0, lastArchivedAt: "" };
|
|
2304
2609
|
try {
|
|
2305
|
-
return JSON.parse(
|
|
2610
|
+
return JSON.parse(readFileSync5(path42, "utf-8"));
|
|
2306
2611
|
} catch {
|
|
2307
2612
|
return { taskCompleted: 0, taskFailed: 0, taskStalled: 0, recoveryAttempted: 0, totalArchived: 0, lastArchivedAt: "" };
|
|
2308
2613
|
}
|
|
@@ -2341,7 +2646,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
2341
2646
|
}
|
|
2342
2647
|
function compactLedger(meshId) {
|
|
2343
2648
|
const filePath = getLedgerPath(meshId);
|
|
2344
|
-
if (!
|
|
2649
|
+
if (!existsSync6(filePath)) return { archivedCount: 0, retainedCount: 0 };
|
|
2345
2650
|
const cutoff = Date.now() - ARCHIVE_TERMINAL_OLDER_THAN_MS;
|
|
2346
2651
|
const entries = readLedgerEntries(meshId);
|
|
2347
2652
|
const keep = [];
|
|
@@ -2356,7 +2661,7 @@ function compactLedger(meshId) {
|
|
|
2356
2661
|
if (archive.length === 0) return { archivedCount: 0, retainedCount: keep.length };
|
|
2357
2662
|
const archivePath = getArchivePath(meshId);
|
|
2358
2663
|
try {
|
|
2359
|
-
if (
|
|
2664
|
+
if (existsSync6(archivePath) && statSync3(archivePath).size > 50 * 1024 * 1024) {
|
|
2360
2665
|
rotateArchiveFile(meshId, archivePath);
|
|
2361
2666
|
}
|
|
2362
2667
|
const archiveLines = archive.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
@@ -2506,9 +2811,9 @@ function appendLedgerEntry(meshId, partial) {
|
|
|
2506
2811
|
...partial
|
|
2507
2812
|
};
|
|
2508
2813
|
const filePath = getLedgerPath(meshId);
|
|
2509
|
-
if (
|
|
2814
|
+
if (existsSync6(filePath)) {
|
|
2510
2815
|
try {
|
|
2511
|
-
const stat2 =
|
|
2816
|
+
const stat2 = statSync3(filePath);
|
|
2512
2817
|
if (stat2.size >= MAX_FILE_SIZE_BYTES) {
|
|
2513
2818
|
rotateLedgerFile(meshId, filePath);
|
|
2514
2819
|
} else if (stat2.size >= COMPACT_THRESHOLD_BYTES) {
|
|
@@ -2604,10 +2909,10 @@ function appendRemoteLedgerEntries(meshId, entries) {
|
|
|
2604
2909
|
}
|
|
2605
2910
|
function readLedgerFile(meshId) {
|
|
2606
2911
|
const filePath = getLedgerPath(meshId);
|
|
2607
|
-
if (!
|
|
2912
|
+
if (!existsSync6(filePath)) return [];
|
|
2608
2913
|
let content;
|
|
2609
2914
|
try {
|
|
2610
|
-
content =
|
|
2915
|
+
content = readFileSync5(filePath, "utf-8");
|
|
2611
2916
|
} catch {
|
|
2612
2917
|
return [];
|
|
2613
2918
|
}
|
|
@@ -2868,7 +3173,7 @@ function getSessionRecoveryContext(meshId, opts) {
|
|
|
2868
3173
|
}
|
|
2869
3174
|
function rotateLedgerFile(meshId, currentPath) {
|
|
2870
3175
|
let index = 1;
|
|
2871
|
-
while (
|
|
3176
|
+
while (existsSync6(getRotatedPath(meshId, index))) {
|
|
2872
3177
|
index++;
|
|
2873
3178
|
if (index > 10) break;
|
|
2874
3179
|
}
|
|
@@ -3539,8 +3844,8 @@ var init_mesh_work_queue = __esm({
|
|
|
3539
3844
|
});
|
|
3540
3845
|
|
|
3541
3846
|
// src/mesh/mesh-runtime-store.ts
|
|
3542
|
-
import { existsSync as
|
|
3543
|
-
import { dirname as dirname2, join as
|
|
3847
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync2, statSync as statSync4 } from "fs";
|
|
3848
|
+
import { dirname as dirname2, join as join8 } from "path";
|
|
3544
3849
|
import { createRequire } from "module";
|
|
3545
3850
|
function loadDatabaseCtor() {
|
|
3546
3851
|
if (DatabaseCtor) return DatabaseCtor;
|
|
@@ -3552,19 +3857,19 @@ function safeMeshId(meshId) {
|
|
|
3552
3857
|
return meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3553
3858
|
}
|
|
3554
3859
|
function legacyQueuePath(meshId) {
|
|
3555
|
-
return
|
|
3860
|
+
return join8(getLedgerDir(), `${safeMeshId(meshId)}.queue.json`);
|
|
3556
3861
|
}
|
|
3557
3862
|
function meshRuntimeStorePath() {
|
|
3558
3863
|
const dir = getLedgerDir();
|
|
3559
|
-
const nextPath =
|
|
3560
|
-
if (
|
|
3561
|
-
const legacyPath =
|
|
3562
|
-
if (!
|
|
3864
|
+
const nextPath = join8(dir, "mesh-runtime.db");
|
|
3865
|
+
if (existsSync7(nextPath)) return nextPath;
|
|
3866
|
+
const legacyPath = join8(dir, "beads.db");
|
|
3867
|
+
if (!existsSync7(legacyPath)) return nextPath;
|
|
3563
3868
|
try {
|
|
3564
3869
|
renameSync2(legacyPath, nextPath);
|
|
3565
3870
|
for (const suffix of ["-wal", "-shm"]) {
|
|
3566
3871
|
const legacyCompanion = `${legacyPath}${suffix}`;
|
|
3567
|
-
if (
|
|
3872
|
+
if (existsSync7(legacyCompanion)) {
|
|
3568
3873
|
renameSync2(legacyCompanion, `${nextPath}${suffix}`);
|
|
3569
3874
|
}
|
|
3570
3875
|
}
|
|
@@ -3590,7 +3895,7 @@ var init_mesh_runtime_store = __esm({
|
|
|
3590
3895
|
// 50 MB
|
|
3591
3896
|
constructor(dbPath) {
|
|
3592
3897
|
const dir = dirname2(dbPath);
|
|
3593
|
-
if (!
|
|
3898
|
+
if (!existsSync7(dir)) mkdirSync4(dir, { recursive: true });
|
|
3594
3899
|
this.dbPath = dbPath;
|
|
3595
3900
|
this.db = new (loadDatabaseCtor())(dbPath);
|
|
3596
3901
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -3845,8 +4150,8 @@ var init_mesh_runtime_store = __esm({
|
|
|
3845
4150
|
this.walWriteCounter = 0;
|
|
3846
4151
|
try {
|
|
3847
4152
|
const walPath = `${this.dbPath}-wal`;
|
|
3848
|
-
if (!
|
|
3849
|
-
const size =
|
|
4153
|
+
if (!existsSync7(walPath)) return;
|
|
4154
|
+
const size = statSync4(walPath).size;
|
|
3850
4155
|
if (size < _MeshRuntimeStore.WAL_MAX_BYTES) return;
|
|
3851
4156
|
process.stderr.write(
|
|
3852
4157
|
`[adhdev-mesh] WAL file ${Math.round(size / 1024 / 1024)}MB exceeds threshold; forcing checkpoint
|
|
@@ -3862,9 +4167,9 @@ var init_mesh_runtime_store = __esm({
|
|
|
3862
4167
|
const count = this.db.prepare("SELECT COUNT(*) AS count FROM mesh_queue WHERE mesh_id = ?").get(meshId);
|
|
3863
4168
|
if (count.count > 0) return;
|
|
3864
4169
|
const path42 = legacyQueuePath(meshId);
|
|
3865
|
-
if (!
|
|
4170
|
+
if (!existsSync7(path42)) return;
|
|
3866
4171
|
try {
|
|
3867
|
-
const entries = JSON.parse(
|
|
4172
|
+
const entries = JSON.parse(readFileSync6(path42, "utf-8"));
|
|
3868
4173
|
if (!Array.isArray(entries)) return;
|
|
3869
4174
|
const insert = this.db.prepare(`
|
|
3870
4175
|
INSERT OR REPLACE INTO mesh_queue (
|
|
@@ -5705,10 +6010,10 @@ __export(mesh_coordinator_exports, {
|
|
|
5705
6010
|
stripCoordinatorWrapperFile: () => stripCoordinatorWrapperFile
|
|
5706
6011
|
});
|
|
5707
6012
|
import { createHash as createHash2 } from "crypto";
|
|
5708
|
-
import { existsSync as
|
|
6013
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
5709
6014
|
import * as os4 from "os";
|
|
5710
6015
|
import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from "@adhdev/session-host-core";
|
|
5711
|
-
import { basename as basename2, isAbsolute as isAbsolute4, join as
|
|
6016
|
+
import { basename as basename2, isAbsolute as isAbsolute4, join as join10, resolve as resolve7 } from "path";
|
|
5712
6017
|
function isHermesProvider(provider, cliType) {
|
|
5713
6018
|
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
5714
6019
|
return type === HERMES_CLI_TYPE;
|
|
@@ -5728,7 +6033,7 @@ function resolveHermesMeshCoordinatorSetup(options) {
|
|
|
5728
6033
|
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
5729
6034
|
};
|
|
5730
6035
|
}
|
|
5731
|
-
const configPath =
|
|
6036
|
+
const configPath = join10(resolveHermesCoordinatorHome(options.meshId, options.workspace), "config.yaml");
|
|
5732
6037
|
if (!configPath.trim()) {
|
|
5733
6038
|
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
5734
6039
|
}
|
|
@@ -5875,14 +6180,14 @@ function resolveHermesCoordinatorHome(meshId, workspace) {
|
|
|
5875
6180
|
const key = `${meshId || "mesh"}
|
|
5876
6181
|
${resolve7(workspace || os4.tmpdir())}`;
|
|
5877
6182
|
const hash = createHash2("sha256").update(key).digest("hex").slice(0, 16);
|
|
5878
|
-
return
|
|
6183
|
+
return join10(os4.tmpdir(), `adhdev-hermes-mesh-coordinator-${hash}`);
|
|
5879
6184
|
}
|
|
5880
6185
|
function resolveMcpConfigPath(configPath, workspace) {
|
|
5881
6186
|
const trimmed = configPath.trim();
|
|
5882
6187
|
if (trimmed === "~") return os4.homedir();
|
|
5883
|
-
if (trimmed.startsWith("~/")) return
|
|
6188
|
+
if (trimmed.startsWith("~/")) return join10(os4.homedir(), trimmed.slice(2));
|
|
5884
6189
|
if (isAbsolute4(trimmed)) return trimmed;
|
|
5885
|
-
return
|
|
6190
|
+
return join10(workspace, trimmed);
|
|
5886
6191
|
}
|
|
5887
6192
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
5888
6193
|
const directEntryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
@@ -5953,7 +6258,7 @@ function applyInjectionRule(systemPrompt, injection, ctx) {
|
|
|
5953
6258
|
}
|
|
5954
6259
|
case "context_file": {
|
|
5955
6260
|
if (!injection.path) return {};
|
|
5956
|
-
const target = isAbsolute4(injection.path) ? injection.path :
|
|
6261
|
+
const target = isAbsolute4(injection.path) ? injection.path : join10(ctx.workspace, injection.path);
|
|
5957
6262
|
const wrapper = injection.wrapper && injection.wrapper.includes("{prompt}") ? injection.wrapper : "{prompt}";
|
|
5958
6263
|
const managedNote = "> _Managed by adhdev mesh coordinator \u2014 do not hand-edit this block. Changes inside the sentinels are overwritten on next coordinator launch._";
|
|
5959
6264
|
const promptWithNote = `${managedNote}
|
|
@@ -5962,8 +6267,8 @@ ${systemPrompt}`;
|
|
|
5962
6267
|
const rendered = wrapper.replace(/\{prompt\}/g, promptWithNote);
|
|
5963
6268
|
const sentinel = wrapper.split("{prompt}")[0].trim();
|
|
5964
6269
|
try {
|
|
5965
|
-
if (
|
|
5966
|
-
const existing =
|
|
6270
|
+
if (existsSync9(target)) {
|
|
6271
|
+
const existing = readFileSync7(target, "utf-8");
|
|
5967
6272
|
if (sentinel && existing.includes(sentinel)) {
|
|
5968
6273
|
const closing = wrapper.split("{prompt}")[1]?.trim();
|
|
5969
6274
|
const safeOpen = sentinel.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
@@ -5993,8 +6298,8 @@ function stripCoordinatorWrapperFile(filePath) {
|
|
|
5993
6298
|
const OPEN = "<!-- adhdev-mesh-coordinator-prompt -->";
|
|
5994
6299
|
const CLOSE = "<!-- /adhdev-mesh-coordinator-prompt -->";
|
|
5995
6300
|
try {
|
|
5996
|
-
if (!
|
|
5997
|
-
const existing =
|
|
6301
|
+
if (!existsSync9(filePath)) return;
|
|
6302
|
+
const existing = readFileSync7(filePath, "utf-8");
|
|
5998
6303
|
const openIdx = existing.indexOf(OPEN);
|
|
5999
6304
|
if (openIdx < 0) return;
|
|
6000
6305
|
const closeIdx = existing.indexOf(CLOSE, openIdx);
|
|
@@ -7428,8 +7733,8 @@ function formatCompletionMetadata(event) {
|
|
|
7428
7733
|
function buildMeshSystemMessage(args) {
|
|
7429
7734
|
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
7430
7735
|
if (args.event === "agent:generating_completed") {
|
|
7431
|
-
if (args.metadataEvent.source === "
|
|
7432
|
-
return `[System] ${args.nodeLabel} already has completion evidence${metadata}. The
|
|
7736
|
+
if (args.metadataEvent.source === "no_progress_reconciliation") {
|
|
7737
|
+
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.`;
|
|
7433
7738
|
}
|
|
7434
7739
|
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.";
|
|
7435
7740
|
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path;${reviewNote}`;
|
|
@@ -7468,7 +7773,7 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
|
|
|
7468
7773
|
}
|
|
7469
7774
|
return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
|
|
7470
7775
|
}
|
|
7471
|
-
if (args.event === "monitor:
|
|
7776
|
+
if (args.event === "monitor:no_progress") {
|
|
7472
7777
|
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.`;
|
|
7473
7778
|
}
|
|
7474
7779
|
if (args.event === "worktree_bootstrap_complete") {
|
|
@@ -7546,8 +7851,8 @@ var init_mesh_events_utils = __esm({
|
|
|
7546
7851
|
});
|
|
7547
7852
|
|
|
7548
7853
|
// src/mesh/mesh-events-pending.ts
|
|
7549
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
7550
|
-
import { join as
|
|
7854
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync13, readFileSync as readFileSync11, renameSync as renameSync4, statSync as statSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
7855
|
+
import { join as join14 } from "path";
|
|
7551
7856
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
7552
7857
|
function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
|
|
7553
7858
|
const raw = Array.isArray(coordinatorDaemonId) ? coordinatorDaemonId : coordinatorDaemonId != null ? [coordinatorDaemonId] : [];
|
|
@@ -7610,9 +7915,9 @@ function getPendingEventsPath(meshId, coordinatorDaemonId) {
|
|
|
7610
7915
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7611
7916
|
if (coordinatorDaemonId) {
|
|
7612
7917
|
const safeDaemon = coordinatorDaemonId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7613
|
-
return
|
|
7918
|
+
return join14(getLedgerDir(), `${safe}-${safeDaemon}.pending-events.jsonl`);
|
|
7614
7919
|
}
|
|
7615
|
-
return
|
|
7920
|
+
return join14(getLedgerDir(), `${safe}.pending-events.jsonl`);
|
|
7616
7921
|
}
|
|
7617
7922
|
function readPendingMeshCoordinatorEventsFromDisk(meshId, coordinatorDaemonId) {
|
|
7618
7923
|
if (!meshId) return [];
|
|
@@ -7621,9 +7926,9 @@ function readPendingMeshCoordinatorEventsFromDisk(meshId, coordinatorDaemonId) {
|
|
|
7621
7926
|
const paths = primaryDaemonId ? [getPendingEventsPath(meshId, primaryDaemonId), getPendingEventsPath(meshId)] : [getPendingEventsPath(meshId)];
|
|
7622
7927
|
const events = [];
|
|
7623
7928
|
for (const path42 of paths) {
|
|
7624
|
-
if (!
|
|
7929
|
+
if (!existsSync13(path42)) continue;
|
|
7625
7930
|
try {
|
|
7626
|
-
const raw =
|
|
7931
|
+
const raw = readFileSync11(path42, "utf-8");
|
|
7627
7932
|
const parsed = raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
7628
7933
|
try {
|
|
7629
7934
|
return [JSON.parse(line)];
|
|
@@ -7698,9 +8003,9 @@ function reconcilePendingMeshCoordinatorEvents(meshId, events) {
|
|
|
7698
8003
|
}
|
|
7699
8004
|
function trimPendingEventsIfNeeded(path42) {
|
|
7700
8005
|
try {
|
|
7701
|
-
if (!
|
|
7702
|
-
if (
|
|
7703
|
-
const lines =
|
|
8006
|
+
if (!existsSync13(path42)) return;
|
|
8007
|
+
if (statSync6(path42).size <= MAX_PENDING_EVENTS_BYTES) return;
|
|
8008
|
+
const lines = readFileSync11(path42, "utf-8").split("\n").filter(Boolean);
|
|
7704
8009
|
if (lines.length <= MAX_PENDING_EVENTS_KEEP) return;
|
|
7705
8010
|
writeFileSync6(path42, lines.slice(-MAX_PENDING_EVENTS_KEEP).join("\n") + "\n", "utf-8");
|
|
7706
8011
|
} catch {
|
|
@@ -7746,7 +8051,7 @@ function atomicDrainFile(path42) {
|
|
|
7746
8051
|
return null;
|
|
7747
8052
|
}
|
|
7748
8053
|
try {
|
|
7749
|
-
const content =
|
|
8054
|
+
const content = readFileSync11(tmpPath, "utf-8");
|
|
7750
8055
|
try {
|
|
7751
8056
|
unlinkSync2(tmpPath);
|
|
7752
8057
|
} catch {
|
|
@@ -7769,7 +8074,7 @@ function selectiveDrainFile(path42, predicate) {
|
|
|
7769
8074
|
}
|
|
7770
8075
|
let content;
|
|
7771
8076
|
try {
|
|
7772
|
-
content =
|
|
8077
|
+
content = readFileSync11(tmpPath, "utf-8");
|
|
7773
8078
|
} catch {
|
|
7774
8079
|
try {
|
|
7775
8080
|
unlinkSync2(tmpPath);
|
|
@@ -7800,7 +8105,7 @@ function selectiveDrainFile(path42, predicate) {
|
|
|
7800
8105
|
unlinkSync2(tmpPath);
|
|
7801
8106
|
} catch {
|
|
7802
8107
|
try {
|
|
7803
|
-
if (
|
|
8108
|
+
if (existsSync13(tmpPath) && !existsSync13(path42)) renameSync4(tmpPath, path42);
|
|
7804
8109
|
} catch {
|
|
7805
8110
|
}
|
|
7806
8111
|
return [];
|
|
@@ -7894,7 +8199,7 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
|
7894
8199
|
}
|
|
7895
8200
|
const paths = coordinatorDaemonId ? [getPendingEventsPath(meshId, coordinatorDaemonId), getPendingEventsPath(meshId)] : [getPendingEventsPath(meshId)];
|
|
7896
8201
|
for (const path42 of paths) {
|
|
7897
|
-
if (
|
|
8202
|
+
if (existsSync13(path42)) try {
|
|
7898
8203
|
unlinkSync2(path42);
|
|
7899
8204
|
} catch {
|
|
7900
8205
|
}
|
|
@@ -8258,7 +8563,7 @@ function reconcileDirectDispatchCompletionFromTranscript(args) {
|
|
|
8258
8563
|
});
|
|
8259
8564
|
return { reconciled: true, kind, workerResult, ledgerEntryId: entry.id };
|
|
8260
8565
|
}
|
|
8261
|
-
function
|
|
8566
|
+
function buildNoProgressCompletionReconciliation(args) {
|
|
8262
8567
|
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
8263
8568
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
8264
8569
|
const providerType = readNonEmptyString2(args.metadataEvent.providerType);
|
|
@@ -8277,8 +8582,8 @@ function buildLongGeneratingCompletionReconciliation(args) {
|
|
|
8277
8582
|
providerType,
|
|
8278
8583
|
providerSessionId,
|
|
8279
8584
|
finalSummary,
|
|
8280
|
-
source: "
|
|
8281
|
-
reconciledFromEvent: "monitor:
|
|
8585
|
+
source: "no_progress_reconciliation",
|
|
8586
|
+
reconciledFromEvent: "monitor:no_progress",
|
|
8282
8587
|
timestamp: args.metadataEvent.timestamp ?? Date.now(),
|
|
8283
8588
|
completionDiagnostic: {
|
|
8284
8589
|
...completionDiagnostic || {},
|
|
@@ -8294,7 +8599,7 @@ function buildLongGeneratingCompletionReconciliation(args) {
|
|
|
8294
8599
|
if (!terminal) return null;
|
|
8295
8600
|
return {
|
|
8296
8601
|
...args.metadataEvent,
|
|
8297
|
-
source: "
|
|
8602
|
+
source: "no_progress_terminal_ledger_suppression",
|
|
8298
8603
|
terminalLedgerKind: terminal.kind,
|
|
8299
8604
|
terminalLedgerAt: terminal.timestamp
|
|
8300
8605
|
};
|
|
@@ -8717,7 +9022,7 @@ var init_provider_cli_shared = __esm({
|
|
|
8717
9022
|
import { exec } from "child_process";
|
|
8718
9023
|
import * as os6 from "os";
|
|
8719
9024
|
import * as path11 from "path";
|
|
8720
|
-
import { existsSync as
|
|
9025
|
+
import { existsSync as existsSync14 } from "fs";
|
|
8721
9026
|
function parseVersion(raw) {
|
|
8722
9027
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
8723
9028
|
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
@@ -8741,7 +9046,7 @@ function resolveCommandPath(command) {
|
|
|
8741
9046
|
if (isExplicitCommandPath(trimmed)) {
|
|
8742
9047
|
const expanded = expandHome(trimmed);
|
|
8743
9048
|
const candidate = path11.isAbsolute(expanded) ? expanded : path11.resolve(expanded);
|
|
8744
|
-
return
|
|
9049
|
+
return existsSync14(candidate) ? candidate : null;
|
|
8745
9050
|
}
|
|
8746
9051
|
return null;
|
|
8747
9052
|
}
|
|
@@ -8751,7 +9056,7 @@ async function resolveDetectionPath(command, whichCmd) {
|
|
|
8751
9056
|
const whichResult = await execAsync(`${whichCmd} ${shellQuote(command)}`);
|
|
8752
9057
|
if (whichResult) return whichResult.split("\n")[0];
|
|
8753
9058
|
const resolved = findBinary(command);
|
|
8754
|
-
if (path11.isAbsolute(resolved) &&
|
|
9059
|
+
if (path11.isAbsolute(resolved) && existsSync14(resolved)) return resolved;
|
|
8755
9060
|
return null;
|
|
8756
9061
|
}
|
|
8757
9062
|
function execAsync(cmd, timeoutMs = 5e3) {
|
|
@@ -9096,7 +9401,7 @@ var init_mesh_unresolved_forward_outbox = __esm({
|
|
|
9096
9401
|
});
|
|
9097
9402
|
|
|
9098
9403
|
// src/mesh/mesh-events-coordinator.ts
|
|
9099
|
-
import { existsSync as
|
|
9404
|
+
import { existsSync as existsSync15 } from "fs";
|
|
9100
9405
|
function resolveCoordinatorDrainDaemonIds(components) {
|
|
9101
9406
|
const ids = /* @__PURE__ */ new Set();
|
|
9102
9407
|
const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
|
|
@@ -9148,7 +9453,7 @@ function hasRecentIntentionalCleanupStop(meshId, sessionId, nodeId) {
|
|
|
9148
9453
|
return false;
|
|
9149
9454
|
}
|
|
9150
9455
|
function shouldSuppressIntentionalCleanupStop(args) {
|
|
9151
|
-
if (args.event !== "agent:stopped" && args.event !== "monitor:
|
|
9456
|
+
if (args.event !== "agent:stopped" && args.event !== "monitor:no_progress") return false;
|
|
9152
9457
|
if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
|
|
9153
9458
|
return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
|
|
9154
9459
|
}
|
|
@@ -9364,7 +9669,7 @@ function resolveAutoFastForwardPolicy(mesh) {
|
|
|
9364
9669
|
function sessionStateLooksActive(state) {
|
|
9365
9670
|
const status = readNonEmptyString2(state?.status).toLowerCase();
|
|
9366
9671
|
const chatStatus = readNonEmptyString2(state?.activeChat?.status).toLowerCase();
|
|
9367
|
-
const active = /* @__PURE__ */ new Set(["generating", "streaming", "long_generating", "working", "starting", "waiting_approval"]);
|
|
9672
|
+
const active = /* @__PURE__ */ new Set(["generating", "streaming", "no_progress", "long_generating", "working", "starting", "waiting_approval"]);
|
|
9368
9673
|
return active.has(status) || active.has(chatStatus);
|
|
9369
9674
|
}
|
|
9370
9675
|
function nodeHasActiveMeshWork(components, meshId, nodeId, currentSessionId) {
|
|
@@ -9884,7 +10189,7 @@ async function maybeAutoFastForwardIdleNode(components, args) {
|
|
|
9884
10189
|
const node = mesh?.nodes?.find((candidate) => meshNodeIdMatches(candidate, args.nodeId));
|
|
9885
10190
|
const workspace = readNonEmptyString2(node?.workspace);
|
|
9886
10191
|
if (!workspace) return;
|
|
9887
|
-
if (!
|
|
10192
|
+
if (!existsSync15(workspace)) return;
|
|
9888
10193
|
const policy = resolveAutoFastForwardPolicy(mesh);
|
|
9889
10194
|
if (!policy.enabled) return;
|
|
9890
10195
|
if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId, args.sessionId)) return;
|
|
@@ -9978,24 +10283,24 @@ function injectMeshSystemMessage(components, args) {
|
|
|
9978
10283
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
9979
10284
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
9980
10285
|
}
|
|
9981
|
-
if (args.event === "monitor:
|
|
9982
|
-
const reconciledCompletion =
|
|
10286
|
+
if (args.event === "monitor:no_progress") {
|
|
10287
|
+
const reconciledCompletion = buildNoProgressCompletionReconciliation({
|
|
9983
10288
|
meshId: args.meshId,
|
|
9984
10289
|
nodeId: args.nodeId,
|
|
9985
10290
|
nodeLabel: args.nodeLabel,
|
|
9986
10291
|
metadataEvent: args.metadataEvent,
|
|
9987
10292
|
sourceInstanceId: args.sourceInstanceId
|
|
9988
10293
|
});
|
|
9989
|
-
if (reconciledCompletion?.source === "
|
|
9990
|
-
LOG.info("MeshEvents", `Reconciled
|
|
10294
|
+
if (reconciledCompletion?.source === "no_progress_reconciliation") {
|
|
10295
|
+
LOG.info("MeshEvents", `Reconciled no-progress monitor to completion for session ${eventSessionId || "(unknown session)"}`);
|
|
9991
10296
|
return injectMeshSystemMessage(components, {
|
|
9992
10297
|
...args,
|
|
9993
10298
|
event: "agent:generating_completed",
|
|
9994
10299
|
metadataEvent: reconciledCompletion
|
|
9995
10300
|
});
|
|
9996
10301
|
}
|
|
9997
|
-
if (reconciledCompletion?.source === "
|
|
9998
|
-
LOG.info("MeshEvents", `Suppressed
|
|
10302
|
+
if (reconciledCompletion?.source === "no_progress_terminal_ledger_suppression") {
|
|
10303
|
+
LOG.info("MeshEvents", `Suppressed no-progress monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
|
|
9999
10304
|
return {
|
|
10000
10305
|
success: true,
|
|
10001
10306
|
forwarded: 0,
|
|
@@ -10037,7 +10342,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
10037
10342
|
const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
|
|
10038
10343
|
const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
|
|
10039
10344
|
const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
10040
|
-
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "
|
|
10345
|
+
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "no_progress_reconciliation") {
|
|
10041
10346
|
LOG.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
10042
10347
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
10043
10348
|
}
|
|
@@ -10515,7 +10820,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
10515
10820
|
"agent:waiting_approval",
|
|
10516
10821
|
"agent:stopped",
|
|
10517
10822
|
"agent:ready",
|
|
10518
|
-
"monitor:
|
|
10823
|
+
"monitor:no_progress",
|
|
10519
10824
|
"refine:accepted",
|
|
10520
10825
|
"refine:completed",
|
|
10521
10826
|
"refine:failed",
|
|
@@ -10526,7 +10831,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
10526
10831
|
"agent:generating_completed": "task_completed",
|
|
10527
10832
|
"agent:waiting_approval": "task_approval_needed",
|
|
10528
10833
|
"agent:stopped": "task_failed",
|
|
10529
|
-
"monitor:
|
|
10834
|
+
"monitor:no_progress": "task_stalled"
|
|
10530
10835
|
};
|
|
10531
10836
|
MESH_FORCE_INJECT_EVENTS = /* @__PURE__ */ new Set([
|
|
10532
10837
|
"agent:generating_completed",
|
|
@@ -12661,7 +12966,7 @@ var init_terminal_screen = __esm({
|
|
|
12661
12966
|
|
|
12662
12967
|
// src/cli-adapters/resolve-executable.ts
|
|
12663
12968
|
import { execFileSync } from "child_process";
|
|
12664
|
-
import { existsSync as
|
|
12969
|
+
import { existsSync as existsSync22 } from "fs";
|
|
12665
12970
|
import * as path18 from "path";
|
|
12666
12971
|
function resolveWin32GlobalBin(trimmed) {
|
|
12667
12972
|
if (path18.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\")) {
|
|
@@ -12677,7 +12982,7 @@ function resolveWin32GlobalBin(trimmed) {
|
|
|
12677
12982
|
if (!dir) continue;
|
|
12678
12983
|
for (const ext of WIN_EXEC_EXT) {
|
|
12679
12984
|
const full = path18.join(dir, trimmed + ext);
|
|
12680
|
-
if (
|
|
12985
|
+
if (existsSync22(full)) return full;
|
|
12681
12986
|
}
|
|
12682
12987
|
}
|
|
12683
12988
|
return null;
|
|
@@ -12686,7 +12991,7 @@ function resolveWin32Executable(command) {
|
|
|
12686
12991
|
if (process.platform !== "win32") return command;
|
|
12687
12992
|
const trimmed = (command || "").trim();
|
|
12688
12993
|
if (!trimmed) return command;
|
|
12689
|
-
if (path18.isAbsolute(trimmed) &&
|
|
12994
|
+
if (path18.isAbsolute(trimmed) && existsSync22(trimmed)) return trimmed;
|
|
12690
12995
|
try {
|
|
12691
12996
|
const out = execFileSync("where", [trimmed], {
|
|
12692
12997
|
encoding: "utf8",
|
|
@@ -15672,7 +15977,7 @@ ${lastSnapshot}`;
|
|
|
15672
15977
|
};
|
|
15673
15978
|
if (parsedSessionStatus === "idle" && hasFinalAssistant(parsedStatusBeforeSend)) return null;
|
|
15674
15979
|
if (this.engine.currentStatus === "generating") return "current_status_generating";
|
|
15675
|
-
if (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating") {
|
|
15980
|
+
if (parsedSessionStatus === "generating" || parsedSessionStatus === "no_progress" || parsedSessionStatus === "long_generating") {
|
|
15676
15981
|
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
15677
15982
|
const parsedHasActionableModal = Boolean(
|
|
15678
15983
|
parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
|
|
@@ -15749,7 +16054,7 @@ ${lastSnapshot}`;
|
|
|
15749
16054
|
}
|
|
15750
16055
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.engine.currentStatus})`);
|
|
15751
16056
|
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
|
|
15752
|
-
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
|
|
16057
|
+
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "no_progress" || parsedSessionStatus === "long_generating")) {
|
|
15753
16058
|
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
15754
16059
|
const parsedHasActionableModal = Boolean(
|
|
15755
16060
|
parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
|
|
@@ -17612,6 +17917,7 @@ init_repo_mesh_types();
|
|
|
17612
17917
|
// src/git/index.ts
|
|
17613
17918
|
init_git_executor();
|
|
17614
17919
|
init_git_status();
|
|
17920
|
+
init_change_impact_config();
|
|
17615
17921
|
init_git_diff();
|
|
17616
17922
|
|
|
17617
17923
|
// src/git/git-summary.ts
|
|
@@ -18906,17 +19212,17 @@ init_mesh_review_inbox();
|
|
|
18906
19212
|
|
|
18907
19213
|
// src/mesh/coordinator-registry.ts
|
|
18908
19214
|
init_config();
|
|
18909
|
-
import { join as
|
|
18910
|
-
import { existsSync as
|
|
19215
|
+
import { join as join11 } from "path";
|
|
19216
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
|
|
18911
19217
|
var _registry = /* @__PURE__ */ new Map();
|
|
18912
19218
|
function getRegistryPath() {
|
|
18913
|
-
return
|
|
19219
|
+
return join11(getDaemonDataDir(), "mesh-coordinators.json");
|
|
18914
19220
|
}
|
|
18915
19221
|
function loadMeshCoordinatorRegistry() {
|
|
18916
19222
|
const path42 = getRegistryPath();
|
|
18917
|
-
if (!
|
|
19223
|
+
if (!existsSync10(path42)) return;
|
|
18918
19224
|
try {
|
|
18919
|
-
const raw = JSON.parse(
|
|
19225
|
+
const raw = JSON.parse(readFileSync8(path42, "utf-8"));
|
|
18920
19226
|
if (!Array.isArray(raw)) return;
|
|
18921
19227
|
_registry.clear();
|
|
18922
19228
|
for (const entry of raw) {
|
|
@@ -18964,9 +19270,9 @@ function listCoordinatorsForWorkspace(workspace) {
|
|
|
18964
19270
|
}
|
|
18965
19271
|
|
|
18966
19272
|
// src/mesh/refine-config.ts
|
|
18967
|
-
import { existsSync as
|
|
18968
|
-
import { join as
|
|
18969
|
-
import * as
|
|
19273
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
|
|
19274
|
+
import { join as join12 } from "path";
|
|
19275
|
+
import * as yaml2 from "js-yaml";
|
|
18970
19276
|
var MESH_REFINE_VALIDATION_CATEGORIES = ["typecheck", "test", "lint", "build"];
|
|
18971
19277
|
var MESH_REFINE_CONFIG_LOCATIONS = [
|
|
18972
19278
|
".adhdev/refine.json",
|
|
@@ -19107,7 +19413,7 @@ function normalizeMeshCommandConfig(entry, source) {
|
|
|
19107
19413
|
}
|
|
19108
19414
|
};
|
|
19109
19415
|
}
|
|
19110
|
-
var
|
|
19416
|
+
var isRecord2 = isMeshConfigRecord;
|
|
19111
19417
|
function validateMeshRefineConfig(config, source = "inline") {
|
|
19112
19418
|
const errors = [];
|
|
19113
19419
|
const bootstrapCommands = [];
|
|
@@ -19115,14 +19421,14 @@ function validateMeshRefineConfig(config, source = "inline") {
|
|
|
19115
19421
|
const rejectedCommands = [];
|
|
19116
19422
|
const deprecationWarnings = [];
|
|
19117
19423
|
let bootstrapMode = "inherit";
|
|
19118
|
-
if (!
|
|
19424
|
+
if (!isRecord2(config)) return { valid: false, errors: ["config must be an object"], bootstrapCommands, commands, rejectedCommands, bootstrapMode, deprecationWarnings };
|
|
19119
19425
|
if (config.version !== 1) errors.push("version must be 1");
|
|
19120
19426
|
if (config.allowAutoPublishSubmoduleMainCommits !== void 0 && typeof config.allowAutoPublishSubmoduleMainCommits !== "boolean") {
|
|
19121
19427
|
errors.push("allowAutoPublishSubmoduleMainCommits must be a boolean when provided");
|
|
19122
19428
|
}
|
|
19123
19429
|
const validation = config.validation;
|
|
19124
|
-
if (validation !== void 0 && !
|
|
19125
|
-
const rawBootstrapMode =
|
|
19430
|
+
if (validation !== void 0 && !isRecord2(validation)) errors.push("validation must be an object");
|
|
19431
|
+
const rawBootstrapMode = isRecord2(validation) ? validation.bootstrap : void 0;
|
|
19126
19432
|
if (rawBootstrapMode !== void 0) {
|
|
19127
19433
|
if (rawBootstrapMode === "inherit" || rawBootstrapMode === "skip") {
|
|
19128
19434
|
bootstrapMode = rawBootstrapMode;
|
|
@@ -19130,8 +19436,8 @@ function validateMeshRefineConfig(config, source = "inline") {
|
|
|
19130
19436
|
errors.push("validation.bootstrap must be 'inherit' or 'skip' when provided");
|
|
19131
19437
|
}
|
|
19132
19438
|
}
|
|
19133
|
-
const rawCommands =
|
|
19134
|
-
const rawBootstrapCommands =
|
|
19439
|
+
const rawCommands = isRecord2(validation) ? validation.commands : void 0;
|
|
19440
|
+
const rawBootstrapCommands = isRecord2(validation) ? validation.bootstrapCommands : void 0;
|
|
19135
19441
|
if (rawCommands !== void 0 && !Array.isArray(rawCommands)) errors.push("validation.commands must be an array");
|
|
19136
19442
|
if (rawBootstrapCommands !== void 0 && !Array.isArray(rawBootstrapCommands)) errors.push("validation.bootstrapCommands must be an array");
|
|
19137
19443
|
if (Array.isArray(rawBootstrapCommands) && rawBootstrapCommands.length > 0) {
|
|
@@ -19154,9 +19460,9 @@ function validateMeshRefineConfig(config, source = "inline") {
|
|
|
19154
19460
|
if (rejectedCommands.length) errors.push("one or more validation commands are invalid");
|
|
19155
19461
|
return { valid: errors.length === 0, errors, bootstrapCommands, commands, rejectedCommands, bootstrapMode, deprecationWarnings };
|
|
19156
19462
|
}
|
|
19157
|
-
function
|
|
19463
|
+
function parseConfigText2(path42, text) {
|
|
19158
19464
|
if (/\.json$/i.test(path42)) return JSON.parse(text);
|
|
19159
|
-
return
|
|
19465
|
+
return yaml2.load(text);
|
|
19160
19466
|
}
|
|
19161
19467
|
function loadMeshRefineConfig(mesh, workspace) {
|
|
19162
19468
|
const policy = mesh?.policy && typeof mesh.policy === "object" && !Array.isArray(mesh.policy) ? mesh.policy : {};
|
|
@@ -19167,10 +19473,10 @@ function loadMeshRefineConfig(mesh, workspace) {
|
|
|
19167
19473
|
return { config: inline, source: "mesh.policy.refineConfig", sourceType: "mesh_policy" };
|
|
19168
19474
|
}
|
|
19169
19475
|
for (const relative5 of MESH_REFINE_CONFIG_LOCATIONS) {
|
|
19170
|
-
const configPath =
|
|
19171
|
-
if (!
|
|
19476
|
+
const configPath = join12(workspace, relative5);
|
|
19477
|
+
if (!existsSync11(configPath)) continue;
|
|
19172
19478
|
try {
|
|
19173
|
-
const parsed =
|
|
19479
|
+
const parsed = parseConfigText2(configPath, readFileSync9(configPath, "utf-8"));
|
|
19174
19480
|
const validation = validateMeshRefineConfig(parsed, relative5);
|
|
19175
19481
|
if (!validation.valid) return { source: relative5, sourceType: "invalid", path: configPath, error: String(validation.rejectedCommands[0]?.reason || validation.errors.join("; ")) };
|
|
19176
19482
|
return { config: parsed, source: relative5, sourceType: "repo_file", path: configPath };
|
|
@@ -19186,20 +19492,20 @@ function loadMeshRefineConfig(mesh, workspace) {
|
|
|
19186
19492
|
}
|
|
19187
19493
|
function readPackageScripts(workspace) {
|
|
19188
19494
|
try {
|
|
19189
|
-
const parsed = JSON.parse(
|
|
19190
|
-
return
|
|
19495
|
+
const parsed = JSON.parse(readFileSync9(join12(workspace, "package.json"), "utf-8"));
|
|
19496
|
+
return isRecord2(parsed?.scripts) ? parsed.scripts : {};
|
|
19191
19497
|
} catch {
|
|
19192
19498
|
return {};
|
|
19193
19499
|
}
|
|
19194
19500
|
}
|
|
19195
19501
|
function collectProjectContextSuggestions(mesh) {
|
|
19196
19502
|
const commands = mesh?.projectContext?.commands;
|
|
19197
|
-
if (!
|
|
19503
|
+
if (!isRecord2(commands)) return [];
|
|
19198
19504
|
const suggestions = [];
|
|
19199
19505
|
for (const category of MESH_REFINE_VALIDATION_CATEGORIES) {
|
|
19200
19506
|
const entries = Array.isArray(commands[category]) ? commands[category] : [];
|
|
19201
19507
|
for (const entry of entries) {
|
|
19202
|
-
if (
|
|
19508
|
+
if (isRecord2(entry) && typeof entry.command === "string") suggestions.push({ command: entry.command, category });
|
|
19203
19509
|
}
|
|
19204
19510
|
}
|
|
19205
19511
|
return suggestions;
|
|
@@ -19263,12 +19569,12 @@ function resolveMeshRefineValidationPlan(mesh, workspace) {
|
|
|
19263
19569
|
}
|
|
19264
19570
|
|
|
19265
19571
|
// src/mesh/worktree-bootstrap-config.ts
|
|
19266
|
-
import { existsSync as
|
|
19267
|
-
import { join as
|
|
19572
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
|
|
19573
|
+
import { join as join13, resolve as pathResolve } from "path";
|
|
19268
19574
|
import { execFile as execFile3 } from "child_process";
|
|
19269
19575
|
import { createHash as createHash3 } from "crypto";
|
|
19270
19576
|
import { promisify as promisify3 } from "util";
|
|
19271
|
-
import * as
|
|
19577
|
+
import * as yaml3 from "js-yaml";
|
|
19272
19578
|
var MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS = [
|
|
19273
19579
|
".adhdev/worktree_bootstrap.json",
|
|
19274
19580
|
".adhdev/worktree_bootstrap.yaml",
|
|
@@ -19313,9 +19619,9 @@ var MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA = {
|
|
|
19313
19619
|
var DEFAULT_TIMEOUT_MS2 = 12e4;
|
|
19314
19620
|
var DEFAULT_OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
19315
19621
|
var OUTPUT_SUMMARY_CHARS = 2e3;
|
|
19316
|
-
function
|
|
19622
|
+
function parseConfigText3(path42, text) {
|
|
19317
19623
|
if (/\.json$/i.test(path42)) return JSON.parse(text);
|
|
19318
|
-
return
|
|
19624
|
+
return yaml3.load(text);
|
|
19319
19625
|
}
|
|
19320
19626
|
function truncateOutput(value) {
|
|
19321
19627
|
const text = typeof value === "string" ? value : value == null ? "" : String(value);
|
|
@@ -19355,10 +19661,10 @@ function loadMeshWorktreeBootstrapConfig(mesh, workspace) {
|
|
|
19355
19661
|
return { config: inline, source: "mesh.policy.worktreeBootstrapConfig", sourceType: "mesh_policy" };
|
|
19356
19662
|
}
|
|
19357
19663
|
for (const relative5 of MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS) {
|
|
19358
|
-
const configPath =
|
|
19359
|
-
if (!
|
|
19664
|
+
const configPath = join13(workspace, relative5);
|
|
19665
|
+
if (!existsSync12(configPath)) continue;
|
|
19360
19666
|
try {
|
|
19361
|
-
const parsed =
|
|
19667
|
+
const parsed = parseConfigText3(configPath, readFileSync10(configPath, "utf-8"));
|
|
19362
19668
|
const validation = validateMeshWorktreeBootstrapConfig(parsed, relative5);
|
|
19363
19669
|
if (!validation.valid) return { source: relative5, sourceType: "invalid", path: configPath, error: String(validation.rejectedCommands[0]?.reason || validation.errors.join("; ")) };
|
|
19364
19670
|
return { config: parsed, source: relative5, sourceType: "repo_file", path: configPath };
|
|
@@ -19371,9 +19677,9 @@ function loadMeshWorktreeBootstrapConfig(mesh, workspace) {
|
|
|
19371
19677
|
function computeStaleInputsDigest(workspace, staleInputs) {
|
|
19372
19678
|
const digest = {};
|
|
19373
19679
|
for (const relative5 of staleInputs ?? []) {
|
|
19374
|
-
const filePath =
|
|
19680
|
+
const filePath = join13(workspace, relative5);
|
|
19375
19681
|
try {
|
|
19376
|
-
digest[relative5] = createHash3("sha256").update(
|
|
19682
|
+
digest[relative5] = createHash3("sha256").update(readFileSync10(filePath)).digest("hex");
|
|
19377
19683
|
} catch {
|
|
19378
19684
|
digest[relative5] = "absent";
|
|
19379
19685
|
}
|
|
@@ -19443,10 +19749,10 @@ async function runMeshWorktreeBootstrap(mesh, workspace) {
|
|
|
19443
19749
|
staleInputs: loaded.config.staleInputs
|
|
19444
19750
|
};
|
|
19445
19751
|
const staleInputPaths = loaded.config.staleInputs ?? [];
|
|
19446
|
-
const initiallyAbsent = staleInputPaths.filter((p) => !
|
|
19752
|
+
const initiallyAbsent = staleInputPaths.filter((p) => !existsSync12(join13(workspace, p)));
|
|
19447
19753
|
for (const command of validation.commands) {
|
|
19448
19754
|
if (initiallyAbsent.length > 0) {
|
|
19449
|
-
const appearedNow = initiallyAbsent.filter((p) =>
|
|
19755
|
+
const appearedNow = initiallyAbsent.filter((p) => existsSync12(join13(workspace, p)));
|
|
19450
19756
|
if (appearedNow.length > 0) {
|
|
19451
19757
|
state.status = "stale";
|
|
19452
19758
|
state.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -19694,8 +20000,8 @@ var P2pRelayFailureError = class extends Error {
|
|
|
19694
20000
|
|
|
19695
20001
|
// src/config/state-store.ts
|
|
19696
20002
|
init_config();
|
|
19697
|
-
import { existsSync as
|
|
19698
|
-
import { join as
|
|
20003
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
|
|
20004
|
+
import { join as join17 } from "path";
|
|
19699
20005
|
var DEFAULT_STATE = {
|
|
19700
20006
|
recentActivity: [],
|
|
19701
20007
|
savedProviderSessions: [],
|
|
@@ -19708,7 +20014,7 @@ function isPlainObject2(value) {
|
|
|
19708
20014
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
19709
20015
|
}
|
|
19710
20016
|
function getStatePath() {
|
|
19711
|
-
return
|
|
20017
|
+
return join17(getConfigDir(), "state.json");
|
|
19712
20018
|
}
|
|
19713
20019
|
function normalizeState(raw) {
|
|
19714
20020
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -19744,11 +20050,11 @@ function normalizeState(raw) {
|
|
|
19744
20050
|
}
|
|
19745
20051
|
function loadState() {
|
|
19746
20052
|
const statePath = getStatePath();
|
|
19747
|
-
if (!
|
|
20053
|
+
if (!existsSync16(statePath)) {
|
|
19748
20054
|
return { ...DEFAULT_STATE };
|
|
19749
20055
|
}
|
|
19750
20056
|
try {
|
|
19751
|
-
const raw =
|
|
20057
|
+
const raw = readFileSync12(statePath, "utf-8");
|
|
19752
20058
|
return normalizeState(JSON.parse(raw));
|
|
19753
20059
|
} catch {
|
|
19754
20060
|
return { ...DEFAULT_STATE };
|
|
@@ -19766,7 +20072,7 @@ function resetState() {
|
|
|
19766
20072
|
// src/detection/ide-detector.ts
|
|
19767
20073
|
import { exec as exec2 } from "child_process";
|
|
19768
20074
|
import { promisify as promisify4 } from "util";
|
|
19769
|
-
import { existsSync as
|
|
20075
|
+
import { existsSync as existsSync18, statSync as statSync8 } from "fs";
|
|
19770
20076
|
import { platform as platform3, homedir as homedir8 } from "os";
|
|
19771
20077
|
import * as path13 from "path";
|
|
19772
20078
|
|
|
@@ -19847,7 +20153,7 @@ function findCliCommand(command) {
|
|
|
19847
20153
|
if (path13.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
19848
20154
|
const candidate = trimmed.startsWith("~") ? path13.join(homedir8(), trimmed.slice(1)) : trimmed;
|
|
19849
20155
|
const resolved = path13.isAbsolute(candidate) ? candidate : path13.resolve(candidate);
|
|
19850
|
-
return
|
|
20156
|
+
return existsSync18(resolved) ? resolved : null;
|
|
19851
20157
|
}
|
|
19852
20158
|
const isWin = platform3() === "win32";
|
|
19853
20159
|
const paths = (process.env.PATH || "").split(isWin ? ";" : ":");
|
|
@@ -19857,8 +20163,8 @@ function findCliCommand(command) {
|
|
|
19857
20163
|
for (const ext of exes) {
|
|
19858
20164
|
const fullPath = path13.join(p, trimmed + ext);
|
|
19859
20165
|
try {
|
|
19860
|
-
if (
|
|
19861
|
-
const stat2 =
|
|
20166
|
+
if (existsSync18(fullPath)) {
|
|
20167
|
+
const stat2 = statSync8(fullPath);
|
|
19862
20168
|
if (stat2.isFile() && (isWin || stat2.mode & 73)) {
|
|
19863
20169
|
return fullPath;
|
|
19864
20170
|
}
|
|
@@ -19876,9 +20182,9 @@ function checkPathExists(paths) {
|
|
|
19876
20182
|
if (normalized.includes("*")) {
|
|
19877
20183
|
const username = home.split(/[\\/]/).pop() || "";
|
|
19878
20184
|
const resolved = normalized.replace("*", username);
|
|
19879
|
-
if (
|
|
20185
|
+
if (existsSync18(resolved)) return resolved;
|
|
19880
20186
|
} else {
|
|
19881
|
-
if (
|
|
20187
|
+
if (existsSync18(normalized)) return normalized;
|
|
19882
20188
|
}
|
|
19883
20189
|
}
|
|
19884
20190
|
return null;
|
|
@@ -19892,7 +20198,7 @@ async function detectIDEs(providerLoader) {
|
|
|
19892
20198
|
let resolvedCli = cliPath;
|
|
19893
20199
|
if (!resolvedCli && appPath && os30 === "darwin") {
|
|
19894
20200
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
19895
|
-
if (
|
|
20201
|
+
if (existsSync18(bundledCli)) resolvedCli = bundledCli;
|
|
19896
20202
|
}
|
|
19897
20203
|
if (!resolvedCli && appPath && os30 === "win32") {
|
|
19898
20204
|
const { dirname: dirname17 } = await import("path");
|
|
@@ -19905,7 +20211,7 @@ async function detectIDEs(providerLoader) {
|
|
|
19905
20211
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
19906
20212
|
];
|
|
19907
20213
|
for (const c of candidates) {
|
|
19908
|
-
if (
|
|
20214
|
+
if (existsSync18(c)) {
|
|
19909
20215
|
resolvedCli = c;
|
|
19910
20216
|
break;
|
|
19911
20217
|
}
|
|
@@ -21450,8 +21756,8 @@ init_contracts();
|
|
|
21450
21756
|
// src/providers/status-monitor.ts
|
|
21451
21757
|
var DEFAULT_MONITOR_CONFIG = {
|
|
21452
21758
|
approvalAlert: true,
|
|
21453
|
-
|
|
21454
|
-
|
|
21759
|
+
noProgressAlert: true,
|
|
21760
|
+
noProgressThresholdSec: 180,
|
|
21455
21761
|
// 3 minutes
|
|
21456
21762
|
alertCooldownSec: 60
|
|
21457
21763
|
// 1 minute cooldown
|
|
@@ -21460,7 +21766,7 @@ var StatusMonitor = class {
|
|
|
21460
21766
|
config;
|
|
21461
21767
|
lastAlertTime = /* @__PURE__ */ new Map();
|
|
21462
21768
|
generatingStartTimes = /* @__PURE__ */ new Map();
|
|
21463
|
-
|
|
21769
|
+
noProgressAlerted = /* @__PURE__ */ new Map();
|
|
21464
21770
|
lastProgressFingerprint = /* @__PURE__ */ new Map();
|
|
21465
21771
|
lastProgressChangeAt = /* @__PURE__ */ new Map();
|
|
21466
21772
|
constructor(config) {
|
|
@@ -21478,7 +21784,7 @@ var StatusMonitor = class {
|
|
|
21478
21784
|
* Check status transition → return notification event array.
|
|
21479
21785
|
* Called from each onTick() or detectStatusTransition().
|
|
21480
21786
|
*/
|
|
21481
|
-
check(agentKey, status, now, progressFingerprint) {
|
|
21787
|
+
check(agentKey, status, now, progressFingerprint, approvalPending) {
|
|
21482
21788
|
const events = [];
|
|
21483
21789
|
if (this.config.approvalAlert && status === "waiting_approval") {
|
|
21484
21790
|
if (this.shouldAlert(agentKey + ":approval", now)) {
|
|
@@ -21491,9 +21797,16 @@ var StatusMonitor = class {
|
|
|
21491
21797
|
}
|
|
21492
21798
|
}
|
|
21493
21799
|
if (status === "generating" || status === "streaming") {
|
|
21800
|
+
if (approvalPending) {
|
|
21801
|
+
this.generatingStartTimes.set(agentKey, now);
|
|
21802
|
+
this.lastProgressFingerprint.set(agentKey, progressFingerprint ?? "");
|
|
21803
|
+
this.lastProgressChangeAt.set(agentKey, now);
|
|
21804
|
+
this.noProgressAlerted.set(agentKey, false);
|
|
21805
|
+
return events;
|
|
21806
|
+
}
|
|
21494
21807
|
if (!this.generatingStartTimes.has(agentKey)) {
|
|
21495
21808
|
this.generatingStartTimes.set(agentKey, now);
|
|
21496
|
-
this.
|
|
21809
|
+
this.noProgressAlerted.set(agentKey, false);
|
|
21497
21810
|
const initialFingerprint = progressFingerprint ?? "";
|
|
21498
21811
|
this.lastProgressFingerprint.set(agentKey, initialFingerprint);
|
|
21499
21812
|
this.lastProgressChangeAt.set(agentKey, now);
|
|
@@ -21503,17 +21816,17 @@ var StatusMonitor = class {
|
|
|
21503
21816
|
if (previousFingerprint !== currentFingerprint) {
|
|
21504
21817
|
this.lastProgressFingerprint.set(agentKey, currentFingerprint);
|
|
21505
21818
|
this.lastProgressChangeAt.set(agentKey, now);
|
|
21506
|
-
this.
|
|
21819
|
+
this.noProgressAlerted.set(agentKey, false);
|
|
21507
21820
|
}
|
|
21508
|
-
if (this.config.
|
|
21821
|
+
if (this.config.noProgressAlert) {
|
|
21509
21822
|
const progressChangedAt = this.lastProgressChangeAt.get(agentKey) || this.generatingStartTimes.get(agentKey);
|
|
21510
21823
|
const elapsedSec = Math.round((now - progressChangedAt) / 1e3);
|
|
21511
|
-
const alreadyAlerted = this.
|
|
21512
|
-
if (elapsedSec > this.config.
|
|
21513
|
-
if (this.shouldAlert(agentKey + ":
|
|
21514
|
-
this.
|
|
21824
|
+
const alreadyAlerted = this.noProgressAlerted.get(agentKey) === true;
|
|
21825
|
+
if (elapsedSec > this.config.noProgressThresholdSec && !alreadyAlerted) {
|
|
21826
|
+
if (this.shouldAlert(agentKey + ":no_progress", now)) {
|
|
21827
|
+
this.noProgressAlerted.set(agentKey, true);
|
|
21515
21828
|
events.push({
|
|
21516
|
-
type: "monitor:
|
|
21829
|
+
type: "monitor:no_progress",
|
|
21517
21830
|
agentKey,
|
|
21518
21831
|
elapsedSec,
|
|
21519
21832
|
timestamp: now,
|
|
@@ -21524,7 +21837,7 @@ var StatusMonitor = class {
|
|
|
21524
21837
|
}
|
|
21525
21838
|
} else {
|
|
21526
21839
|
this.generatingStartTimes.delete(agentKey);
|
|
21527
|
-
this.
|
|
21840
|
+
this.noProgressAlerted.delete(agentKey);
|
|
21528
21841
|
this.lastProgressFingerprint.delete(agentKey);
|
|
21529
21842
|
this.lastProgressChangeAt.delete(agentKey);
|
|
21530
21843
|
}
|
|
@@ -21543,7 +21856,7 @@ var StatusMonitor = class {
|
|
|
21543
21856
|
reset(agentKey) {
|
|
21544
21857
|
if (agentKey) {
|
|
21545
21858
|
this.generatingStartTimes.delete(agentKey);
|
|
21546
|
-
this.
|
|
21859
|
+
this.noProgressAlerted.delete(agentKey);
|
|
21547
21860
|
this.lastProgressFingerprint.delete(agentKey);
|
|
21548
21861
|
this.lastProgressChangeAt.delete(agentKey);
|
|
21549
21862
|
for (const k of this.lastAlertTime.keys()) {
|
|
@@ -21551,7 +21864,7 @@ var StatusMonitor = class {
|
|
|
21551
21864
|
}
|
|
21552
21865
|
} else {
|
|
21553
21866
|
this.generatingStartTimes.clear();
|
|
21554
|
-
this.
|
|
21867
|
+
this.noProgressAlerted.clear();
|
|
21555
21868
|
this.lastProgressFingerprint.clear();
|
|
21556
21869
|
this.lastProgressChangeAt.clear();
|
|
21557
21870
|
this.lastAlertTime.clear();
|
|
@@ -23374,8 +23687,8 @@ var ExtensionProviderInstance = class {
|
|
|
23374
23687
|
this.settings = context.settings || {};
|
|
23375
23688
|
this.monitor.updateConfig({
|
|
23376
23689
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
23377
|
-
|
|
23378
|
-
|
|
23690
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
23691
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
23379
23692
|
});
|
|
23380
23693
|
}
|
|
23381
23694
|
async onTick() {
|
|
@@ -23466,8 +23779,8 @@ var ExtensionProviderInstance = class {
|
|
|
23466
23779
|
this.settings = { ...this.settings, ...newSettings };
|
|
23467
23780
|
this.monitor.updateConfig({
|
|
23468
23781
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
23469
|
-
|
|
23470
|
-
|
|
23782
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
23783
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
23471
23784
|
});
|
|
23472
23785
|
}
|
|
23473
23786
|
/** Query UUID instanceId */
|
|
@@ -23527,7 +23840,8 @@ var ExtensionProviderInstance = class {
|
|
|
23527
23840
|
phase: agentStatus === "idle" && (previousStatus === "generating" || previousStatus === "waiting_approval") ? "turn_completed" : "immediate"
|
|
23528
23841
|
});
|
|
23529
23842
|
const agentKey = `${this.type}:ext`;
|
|
23530
|
-
const
|
|
23843
|
+
const approvalPending = agentStatus === "waiting_approval";
|
|
23844
|
+
const monitorEvents = this.monitor.check(agentKey, agentStatus, now, progressFingerprint, approvalPending);
|
|
23531
23845
|
for (const me of monitorEvents) {
|
|
23532
23846
|
this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
|
|
23533
23847
|
}
|
|
@@ -23742,7 +24056,7 @@ init_contracts();
|
|
|
23742
24056
|
var CHAT_CONTRACT_VERSION_V1 = "1.0";
|
|
23743
24057
|
|
|
23744
24058
|
// src/providers/read-chat-contract.ts
|
|
23745
|
-
var VALID_STATUSES = ["idle", "generating", "waiting_approval", "error", "panel_hidden", "starting", "streaming", "long_generating"];
|
|
24059
|
+
var VALID_STATUSES = ["idle", "generating", "waiting_approval", "error", "panel_hidden", "starting", "streaming", "no_progress", "long_generating"];
|
|
23746
24060
|
var VALID_ROLES = ["user", "assistant", "system", "human"];
|
|
23747
24061
|
var VALID_BUBBLE_STATES = ["draft", "streaming", "final", "removed"];
|
|
23748
24062
|
var VALID_TURN_STATUSES = ["open", "waiting_approval", "complete", "error"];
|
|
@@ -24009,8 +24323,8 @@ var IdeProviderInstance = class {
|
|
|
24009
24323
|
this.settings = context.settings || {};
|
|
24010
24324
|
this.monitor.updateConfig({
|
|
24011
24325
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
24012
|
-
|
|
24013
|
-
|
|
24326
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
24327
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
24014
24328
|
});
|
|
24015
24329
|
}
|
|
24016
24330
|
async onTick() {
|
|
@@ -24137,8 +24451,8 @@ var IdeProviderInstance = class {
|
|
|
24137
24451
|
this.settings = { ...this.settings, ...newSettings };
|
|
24138
24452
|
this.monitor.updateConfig({
|
|
24139
24453
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
24140
|
-
|
|
24141
|
-
|
|
24454
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
24455
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
24142
24456
|
});
|
|
24143
24457
|
}
|
|
24144
24458
|
// ─── Extension manage ─────────────────────────────
|
|
@@ -24269,7 +24583,7 @@ var IdeProviderInstance = class {
|
|
|
24269
24583
|
const persistedMessages = chat.messages || messages;
|
|
24270
24584
|
if (persistedMessages.length > 0) {
|
|
24271
24585
|
let toSave = persistedMessages;
|
|
24272
|
-
if (chat.status === "generating" || chat.status === "long_generating") {
|
|
24586
|
+
if (chat.status === "generating" || chat.status === "no_progress" || chat.status === "long_generating") {
|
|
24273
24587
|
const lastIdx = toSave.length - 1;
|
|
24274
24588
|
if (lastIdx >= 0 && toSave[lastIdx].role === "assistant") {
|
|
24275
24589
|
toSave = toSave.slice(0, lastIdx);
|
|
@@ -24339,7 +24653,8 @@ var IdeProviderInstance = class {
|
|
|
24339
24653
|
if (rawAgentStatus === "waiting_approval" && autoApproveActive && !this.autoApproveBusy) {
|
|
24340
24654
|
this.autoApproveViaScript(chatData);
|
|
24341
24655
|
}
|
|
24342
|
-
const
|
|
24656
|
+
const approvalPending = rawAgentStatus === "waiting_approval";
|
|
24657
|
+
const monitorEvents = this.monitor.check(agentKey, agentStatus, now, progressFingerprint, approvalPending);
|
|
24343
24658
|
for (const me of monitorEvents) {
|
|
24344
24659
|
this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
|
|
24345
24660
|
}
|
|
@@ -26896,7 +27211,7 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
26896
27211
|
}
|
|
26897
27212
|
}
|
|
26898
27213
|
function isGeneratingLikeStatus(status) {
|
|
26899
|
-
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
27214
|
+
return status === "generating" || status === "streaming" || status === "no_progress" || status === "long_generating" || status === "starting";
|
|
26900
27215
|
}
|
|
26901
27216
|
function hasVisibleAssistantMessage(messages) {
|
|
26902
27217
|
if (!Array.isArray(messages)) return false;
|
|
@@ -30932,7 +31247,7 @@ init_config();
|
|
|
30932
31247
|
import * as os19 from "os";
|
|
30933
31248
|
import * as path26 from "path";
|
|
30934
31249
|
import * as crypto5 from "crypto";
|
|
30935
|
-
import { existsSync as
|
|
31250
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync12, writeFileSync as writeFileSync15 } from "fs";
|
|
30936
31251
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
30937
31252
|
import chalk from "chalk";
|
|
30938
31253
|
|
|
@@ -33574,7 +33889,7 @@ function hasNonEmptyCliModalButtons(activeModal) {
|
|
|
33574
33889
|
return Array.isArray(buttons) && buttons.some((button) => String(button || "").trim().length > 0);
|
|
33575
33890
|
}
|
|
33576
33891
|
function isCliGeneratingLikeStatus(status) {
|
|
33577
|
-
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
33892
|
+
return status === "generating" || status === "streaming" || status === "no_progress" || status === "long_generating" || status === "starting";
|
|
33578
33893
|
}
|
|
33579
33894
|
function buildCliStructuredInputPrompt(input, options = {}) {
|
|
33580
33895
|
const promptParts = [];
|
|
@@ -33776,8 +34091,8 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
33776
34091
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
33777
34092
|
this.monitor.updateConfig({
|
|
33778
34093
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
33779
|
-
|
|
33780
|
-
|
|
34094
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
34095
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
33781
34096
|
});
|
|
33782
34097
|
if (context.serverConn) {
|
|
33783
34098
|
this.adapter.setServerConn(context.serverConn);
|
|
@@ -33924,7 +34239,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
33924
34239
|
if (parsedMessages.length > 0) {
|
|
33925
34240
|
const shouldSkipReplayPersist = this.suppressIdleHistoryReplay && adapterStatus.status === "idle" && parsedStatus?.status === "idle";
|
|
33926
34241
|
let messagesToSave = parsedMessages;
|
|
33927
|
-
if (!suppressStaleParsedBusyStatus && (parsedChatStatus === "generating" || parsedChatStatus === "long_generating")) {
|
|
34242
|
+
if (!suppressStaleParsedBusyStatus && (parsedChatStatus === "generating" || parsedChatStatus === "no_progress" || parsedChatStatus === "long_generating")) {
|
|
33928
34243
|
const lastIdx = messagesToSave.length - 1;
|
|
33929
34244
|
if (lastIdx >= 0 && messagesToSave[lastIdx]?.role === "assistant") {
|
|
33930
34245
|
messagesToSave = messagesToSave.slice(0, lastIdx);
|
|
@@ -34052,8 +34367,8 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
34052
34367
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
34053
34368
|
this.monitor.updateConfig({
|
|
34054
34369
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
34055
|
-
|
|
34056
|
-
|
|
34370
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
34371
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
34057
34372
|
});
|
|
34058
34373
|
}
|
|
34059
34374
|
/**
|
|
@@ -34785,10 +35100,11 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
34785
35100
|
phase: newStatus === "idle" && (previousStatus === "generating" || previousStatus === "waiting_approval") ? "turn_completed" : "immediate"
|
|
34786
35101
|
});
|
|
34787
35102
|
const agentKey = `${this.type}:cli`;
|
|
34788
|
-
const
|
|
35103
|
+
const approvalPending = rawStatus === "waiting_approval";
|
|
35104
|
+
const monitorEvents = this.monitor.check(agentKey, newStatus, now, progressFingerprint, approvalPending);
|
|
34789
35105
|
const monitorParsedStatus = parsedStatus;
|
|
34790
35106
|
for (const me of monitorEvents) {
|
|
34791
|
-
if (me.type === "monitor:
|
|
35107
|
+
if (me.type === "monitor:no_progress" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
|
|
34792
35108
|
this.pushEvent({
|
|
34793
35109
|
event: "agent:generating_completed",
|
|
34794
35110
|
chatTitle,
|
|
@@ -34799,7 +35115,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
34799
35115
|
providerType: this.type,
|
|
34800
35116
|
sessionId: this.instanceId,
|
|
34801
35117
|
providerSessionId: this.providerSessionId || null,
|
|
34802
|
-
reconciliationReason: "
|
|
35118
|
+
reconciliationReason: "no_progress_monitor_final_summary",
|
|
34803
35119
|
finalAssistantPresent: true
|
|
34804
35120
|
}
|
|
34805
35121
|
});
|
|
@@ -35481,8 +35797,8 @@ var AcpProviderInstance = class {
|
|
|
35481
35797
|
this.settings = context.settings || {};
|
|
35482
35798
|
this.monitor.updateConfig({
|
|
35483
35799
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
35484
|
-
|
|
35485
|
-
|
|
35800
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
35801
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
35486
35802
|
});
|
|
35487
35803
|
await this.spawnAgent();
|
|
35488
35804
|
}
|
|
@@ -35778,8 +36094,8 @@ var AcpProviderInstance = class {
|
|
|
35778
36094
|
this.settings = { ...this.settings, ...newSettings };
|
|
35779
36095
|
this.monitor.updateConfig({
|
|
35780
36096
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
35781
|
-
|
|
35782
|
-
|
|
36097
|
+
noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
|
|
36098
|
+
noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180
|
|
35783
36099
|
});
|
|
35784
36100
|
this.log.info(`[${this.type}] Settings updated: ${Object.keys(newSettings).join(", ")}`);
|
|
35785
36101
|
}
|
|
@@ -36486,7 +36802,8 @@ ${rawInput}` : rawInput;
|
|
|
36486
36802
|
this.lastStatus = newStatus;
|
|
36487
36803
|
}
|
|
36488
36804
|
const agentKey = `${this.type}:acp`;
|
|
36489
|
-
const
|
|
36805
|
+
const approvalPending = newStatus === "waiting_approval";
|
|
36806
|
+
const monitorEvents = this.monitor.check(agentKey, newStatus, now, progressFingerprint, approvalPending);
|
|
36490
36807
|
for (const me of monitorEvents) {
|
|
36491
36808
|
this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
|
|
36492
36809
|
}
|
|
@@ -36548,7 +36865,7 @@ function commandExists(command) {
|
|
|
36548
36865
|
const trimmed = command.trim();
|
|
36549
36866
|
if (!trimmed) return false;
|
|
36550
36867
|
if (isExplicitCommand(trimmed)) {
|
|
36551
|
-
return
|
|
36868
|
+
return existsSync27(expandExecutable(trimmed));
|
|
36552
36869
|
}
|
|
36553
36870
|
try {
|
|
36554
36871
|
execFileSync2(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -36560,7 +36877,7 @@ function commandExists(command) {
|
|
|
36560
36877
|
return false;
|
|
36561
36878
|
}
|
|
36562
36879
|
}
|
|
36563
|
-
var BUSY_AGENT_STATUSES = /* @__PURE__ */ new Set(["generating", "running", "streaming", "starting", "busy", "waiting", "waiting_approval", "long_generating"]);
|
|
36880
|
+
var BUSY_AGENT_STATUSES = /* @__PURE__ */ new Set(["generating", "running", "streaming", "starting", "busy", "waiting", "waiting_approval", "no_progress", "long_generating"]);
|
|
36564
36881
|
var ZERO_MESSAGE_STARTING_SEND_WAIT_MS = 2e3;
|
|
36565
36882
|
function normalizeAgentStatus(value) {
|
|
36566
36883
|
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
@@ -41425,6 +41742,7 @@ function getAvailableIdeIds() {
|
|
|
41425
41742
|
init_config();
|
|
41426
41743
|
init_cli_detector();
|
|
41427
41744
|
init_git_status();
|
|
41745
|
+
init_change_impact_config();
|
|
41428
41746
|
init_dist();
|
|
41429
41747
|
init_logger();
|
|
41430
41748
|
|
|
@@ -41574,7 +41892,7 @@ cleanOldFiles();
|
|
|
41574
41892
|
|
|
41575
41893
|
// src/commands/router.ts
|
|
41576
41894
|
init_logger();
|
|
41577
|
-
import * as
|
|
41895
|
+
import * as yaml4 from "js-yaml";
|
|
41578
41896
|
|
|
41579
41897
|
// src/logging/log-tail-reader.ts
|
|
41580
41898
|
init_logger();
|
|
@@ -41875,7 +42193,7 @@ function orderMeshRefineBatchNodes(changeAreas) {
|
|
|
41875
42193
|
|
|
41876
42194
|
// src/mesh/preview-freshness.ts
|
|
41877
42195
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
41878
|
-
import { existsSync as
|
|
42196
|
+
import { existsSync as existsSync36, readFileSync as readFileSync27 } from "fs";
|
|
41879
42197
|
import { resolve as resolve19 } from "path";
|
|
41880
42198
|
var PREVIEW_DEPLOY_RECORD = ".adhdev/preview-deploy.json";
|
|
41881
42199
|
function runGit2(repoRoot, args) {
|
|
@@ -41892,9 +42210,9 @@ function runGit2(repoRoot, args) {
|
|
|
41892
42210
|
}
|
|
41893
42211
|
function readRecord6(repoRoot) {
|
|
41894
42212
|
const path42 = resolve19(repoRoot, PREVIEW_DEPLOY_RECORD);
|
|
41895
|
-
if (!
|
|
42213
|
+
if (!existsSync36(path42)) return null;
|
|
41896
42214
|
try {
|
|
41897
|
-
const parsed = JSON.parse(
|
|
42215
|
+
const parsed = JSON.parse(readFileSync27(path42, "utf8"));
|
|
41898
42216
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
41899
42217
|
} catch {
|
|
41900
42218
|
return null;
|
|
@@ -41959,8 +42277,8 @@ function buildPreviewFreshness(repoRoot) {
|
|
|
41959
42277
|
init_mesh_refine_status();
|
|
41960
42278
|
|
|
41961
42279
|
// src/mesh/mesh-init.ts
|
|
41962
|
-
import { existsSync as
|
|
41963
|
-
import { dirname as dirname10, join as
|
|
42280
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync15, writeFileSync as writeFileSync17 } from "fs";
|
|
42281
|
+
import { dirname as dirname10, join as join40 } from "path";
|
|
41964
42282
|
var MESH_INIT_REFINE_CONFIG_PATH = MESH_REFINE_CONFIG_LOCATIONS[0];
|
|
41965
42283
|
var MESH_INIT_WORKTREE_BOOTSTRAP_CONFIG_PATH = MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS[0];
|
|
41966
42284
|
var CANDIDATE_STALE_INPUTS = [
|
|
@@ -41974,7 +42292,7 @@ var CANDIDATE_STALE_INPUTS = [
|
|
|
41974
42292
|
"requirements.txt"
|
|
41975
42293
|
];
|
|
41976
42294
|
function writeConfigFile(workspace, relativePath, config) {
|
|
41977
|
-
const target =
|
|
42295
|
+
const target = join40(workspace, relativePath);
|
|
41978
42296
|
mkdirSync15(dirname10(target), { recursive: true });
|
|
41979
42297
|
writeFileSync17(target, `${JSON.stringify(config, null, 2)}
|
|
41980
42298
|
`, "utf-8");
|
|
@@ -41982,14 +42300,14 @@ function writeConfigFile(workspace, relativePath, config) {
|
|
|
41982
42300
|
}
|
|
41983
42301
|
function suggestMeshWorktreeBootstrapConfig(workspace) {
|
|
41984
42302
|
const commands = [];
|
|
41985
|
-
const hasPackageJson =
|
|
41986
|
-
const hasNpmLock =
|
|
42303
|
+
const hasPackageJson = existsSync37(join40(workspace, "package.json"));
|
|
42304
|
+
const hasNpmLock = existsSync37(join40(workspace, "package-lock.json"));
|
|
41987
42305
|
if (hasPackageJson) {
|
|
41988
42306
|
commands.push(
|
|
41989
42307
|
hasNpmLock ? { command: "npm", args: ["ci"] } : { command: "npm", args: ["install"] }
|
|
41990
42308
|
);
|
|
41991
42309
|
}
|
|
41992
|
-
const staleInputs = CANDIDATE_STALE_INPUTS.filter((relative5) =>
|
|
42310
|
+
const staleInputs = CANDIDATE_STALE_INPUTS.filter((relative5) => existsSync37(join40(workspace, relative5)));
|
|
41993
42311
|
if (!commands.length) {
|
|
41994
42312
|
return { commands, staleInputs };
|
|
41995
42313
|
}
|
|
@@ -42057,7 +42375,7 @@ function runMeshInit(mesh, workspace, detected, options = {}) {
|
|
|
42057
42375
|
}
|
|
42058
42376
|
function applyConfigSuggestion(input) {
|
|
42059
42377
|
const { workspace, relativePath, existing, suggestedConfig, validate, write, overwrite } = input;
|
|
42060
|
-
const absolute =
|
|
42378
|
+
const absolute = join40(workspace, relativePath);
|
|
42061
42379
|
if (existing !== void 0 && !overwrite) {
|
|
42062
42380
|
return { path: absolute, relativePath, written: false, skippedReason: "already_exists", config: existing };
|
|
42063
42381
|
}
|
|
@@ -44856,7 +45174,7 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
44856
45174
|
return summary;
|
|
44857
45175
|
}
|
|
44858
45176
|
function loadYamlModule() {
|
|
44859
|
-
return
|
|
45177
|
+
return yaml4;
|
|
44860
45178
|
}
|
|
44861
45179
|
function getMcpServersKey(format) {
|
|
44862
45180
|
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
@@ -48598,6 +48916,42 @@ ${hintLines.join("\n")}` : "",
|
|
|
48598
48916
|
note: "Suggestions are heuristic scaffold only; Refinery will not execute them until saved into repo mesh/refine config."
|
|
48599
48917
|
};
|
|
48600
48918
|
}
|
|
48919
|
+
case "get_mesh_change_impact_config_schema": {
|
|
48920
|
+
return {
|
|
48921
|
+
success: true,
|
|
48922
|
+
schema: CHANGE_IMPACT_CONFIG_SCHEMA,
|
|
48923
|
+
locations: CHANGE_IMPACT_CONFIG_LOCATIONS,
|
|
48924
|
+
sourceOfTruth: "repo change-impact config",
|
|
48925
|
+
heuristicRole: "suggestions_only_not_execution_path",
|
|
48926
|
+
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."
|
|
48927
|
+
};
|
|
48928
|
+
}
|
|
48929
|
+
case "validate_mesh_change_impact_config": {
|
|
48930
|
+
const workspace = typeof args?.workspace === "string" ? args.workspace : process.cwd();
|
|
48931
|
+
if (args?.config !== void 0) {
|
|
48932
|
+
const validation = validateChangeImpactConfig(args.config, "inline");
|
|
48933
|
+
return { success: validation.valid, source: "inline", sourceType: "mesh_policy", ...validation };
|
|
48934
|
+
}
|
|
48935
|
+
const loaded = loadChangeImpactConfig(workspace);
|
|
48936
|
+
if (loaded.sourceType === "repo_file") {
|
|
48937
|
+
const validation = validateChangeImpactConfig(loaded.config, loaded.source);
|
|
48938
|
+
return { success: validation.valid, ...loaded, ...validation };
|
|
48939
|
+
}
|
|
48940
|
+
return {
|
|
48941
|
+
success: false,
|
|
48942
|
+
...loaded,
|
|
48943
|
+
valid: false,
|
|
48944
|
+
errors: [loaded.error || "repo change-impact config unavailable"]
|
|
48945
|
+
};
|
|
48946
|
+
}
|
|
48947
|
+
case "suggest_mesh_change_impact_config": {
|
|
48948
|
+
const workspace = typeof args?.workspace === "string" ? args.workspace : process.cwd();
|
|
48949
|
+
return {
|
|
48950
|
+
success: true,
|
|
48951
|
+
...suggestChangeImpactConfig(workspace),
|
|
48952
|
+
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."
|
|
48953
|
+
};
|
|
48954
|
+
}
|
|
48601
48955
|
case "mesh_init": {
|
|
48602
48956
|
const workspace = typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : process.cwd();
|
|
48603
48957
|
const mesh = args?.inlineMesh || {};
|
|
@@ -49514,7 +49868,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
49514
49868
|
workspace
|
|
49515
49869
|
};
|
|
49516
49870
|
}
|
|
49517
|
-
const { existsSync:
|
|
49871
|
+
const { existsSync: existsSync46, readFileSync: readFileSync37, writeFileSync: writeFileSync23, copyFileSync: copyFileSync4, mkdirSync: mkdirSync21 } = await import("fs");
|
|
49518
49872
|
const { dirname: dirname17 } = await import("path");
|
|
49519
49873
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
49520
49874
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
@@ -49557,14 +49911,14 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
49557
49911
|
if (hermesManualFallback) return returnManualFallback(message);
|
|
49558
49912
|
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
49559
49913
|
}
|
|
49560
|
-
const hadExistingMcpConfig =
|
|
49914
|
+
const hadExistingMcpConfig = existsSync46(mcpConfigPath);
|
|
49561
49915
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
49562
49916
|
if (hermesBaseConfig) {
|
|
49563
49917
|
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname17(mcpConfigPath));
|
|
49564
49918
|
}
|
|
49565
49919
|
if (hadExistingMcpConfig) {
|
|
49566
49920
|
try {
|
|
49567
|
-
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
49921
|
+
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync37(mcpConfigPath, "utf-8"), configFormat);
|
|
49568
49922
|
const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
|
|
49569
49923
|
existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
|
|
49570
49924
|
copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
|
|
@@ -50063,7 +50417,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
50063
50417
|
const { deriveMeshReviewInboxItems: deriveMeshReviewInboxItems2 } = await Promise.resolve().then(() => (init_mesh_review_inbox(), mesh_review_inbox_exports));
|
|
50064
50418
|
const { readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
50065
50419
|
const { getGitDiffSummary: getGitDiffSummary2 } = await Promise.resolve().then(() => (init_git_diff(), git_diff_exports));
|
|
50066
|
-
const { existsSync:
|
|
50420
|
+
const { existsSync: existsSync46 } = await import("fs");
|
|
50067
50421
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
50068
50422
|
const mesh = meshRecord?.mesh;
|
|
50069
50423
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
@@ -50082,7 +50436,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
50082
50436
|
const derivation = deriveMeshReviewInboxItems2({ nodes: nodeStatuses, ledgerEntries });
|
|
50083
50437
|
for (const item of derivation.items) {
|
|
50084
50438
|
const workspace = item.workspace;
|
|
50085
|
-
if (!workspace || !
|
|
50439
|
+
if (!workspace || !existsSync46(workspace)) continue;
|
|
50086
50440
|
const baseRef = item.defaultBranch ? `origin/${item.defaultBranch}` : "origin/main";
|
|
50087
50441
|
try {
|
|
50088
50442
|
const diffResult = await getGitDiffSummary2(workspace, { baseRef, maxFiles: 100 });
|
|
@@ -50256,7 +50610,7 @@ var DaemonStatusReporter = class {
|
|
|
50256
50610
|
case "agent:waiting_approval":
|
|
50257
50611
|
case "agent:generating_completed":
|
|
50258
50612
|
case "agent:stopped":
|
|
50259
|
-
case "monitor:
|
|
50613
|
+
case "monitor:no_progress":
|
|
50260
50614
|
return value;
|
|
50261
50615
|
default:
|
|
50262
50616
|
return null;
|
|
@@ -50801,7 +51155,7 @@ var ProviderStreamAdapter = class {
|
|
|
50801
51155
|
}
|
|
50802
51156
|
const validated = validateReadChatResultPayload(data, `${this.agentType} readChat`);
|
|
50803
51157
|
const validatedStatus = validated.status;
|
|
50804
|
-
const streamStatus = validatedStatus === "generating" || validatedStatus === "long_generating" ? "streaming" : validatedStatus;
|
|
51158
|
+
const streamStatus = validatedStatus === "generating" || validatedStatus === "no_progress" || validatedStatus === "long_generating" ? "streaming" : validatedStatus;
|
|
50805
51159
|
const state = {
|
|
50806
51160
|
agentType: this.agentType,
|
|
50807
51161
|
agentName: this.agentName,
|
|
@@ -58641,12 +58995,12 @@ init_parse_session();
|
|
|
58641
58995
|
|
|
58642
58996
|
// src/providers/sdk/v1/fixture-tooling/replay.ts
|
|
58643
58997
|
init_provider_cli_shared();
|
|
58644
|
-
import { readFileSync as
|
|
58998
|
+
import { readFileSync as readFileSync35 } from "fs";
|
|
58645
58999
|
import { dirname as dirname15, resolve as resolve22 } from "path";
|
|
58646
59000
|
|
|
58647
59001
|
// src/providers/sdk/v1/validators/taint.ts
|
|
58648
|
-
import { readFileSync as
|
|
58649
|
-
import { resolve as resolve23, dirname as dirname16, join as
|
|
59002
|
+
import { readFileSync as readFileSync36, existsSync as existsSync45 } from "fs";
|
|
59003
|
+
import { resolve as resolve23, dirname as dirname16, join as join47 } from "path";
|
|
58650
59004
|
|
|
58651
59005
|
// src/providers/sdk/v1/validators/index.ts
|
|
58652
59006
|
init_manifest();
|
|
@@ -58726,6 +59080,8 @@ export {
|
|
|
58726
59080
|
AcpProviderInstance,
|
|
58727
59081
|
AgentStreamPoller,
|
|
58728
59082
|
BUILTIN_CHAT_MESSAGE_KINDS,
|
|
59083
|
+
CHANGE_IMPACT_CONFIG_LOCATIONS,
|
|
59084
|
+
CHANGE_IMPACT_CONFIG_SCHEMA,
|
|
58729
59085
|
CHAT_MESSAGE_ACTIVITY_SOURCES,
|
|
58730
59086
|
CHAT_MESSAGE_AUDIENCES,
|
|
58731
59087
|
CHAT_MESSAGE_INTERNAL_SOURCES,
|
|
@@ -58916,6 +59272,7 @@ export {
|
|
|
58916
59272
|
getSessionHostSurfaceKind,
|
|
58917
59273
|
getSessionRecoveryContext,
|
|
58918
59274
|
getWorkspaceState,
|
|
59275
|
+
globToRegExp,
|
|
58919
59276
|
handleGitCommand,
|
|
58920
59277
|
hasCdpManager,
|
|
58921
59278
|
hasPendingDependents,
|
|
@@ -58949,6 +59306,7 @@ export {
|
|
|
58949
59306
|
listMeshMissionSummaries,
|
|
58950
59307
|
listMeshes,
|
|
58951
59308
|
listWorktrees,
|
|
59309
|
+
loadChangeImpactConfig,
|
|
58952
59310
|
loadConfig,
|
|
58953
59311
|
loadMeshCoordinatorRegistry,
|
|
58954
59312
|
loadMeshRefineConfig,
|
|
@@ -59043,6 +59401,7 @@ export {
|
|
|
59043
59401
|
spawnDetachedDaemonUpgradeHelper,
|
|
59044
59402
|
startDaemonDevSupport,
|
|
59045
59403
|
startLocalIpcServer,
|
|
59404
|
+
suggestChangeImpactConfig,
|
|
59046
59405
|
suggestMeshRefineConfig,
|
|
59047
59406
|
summarizeGitStatus,
|
|
59048
59407
|
summarizeMeshAsyncRefineJobs,
|
|
@@ -59059,6 +59418,7 @@ export {
|
|
|
59059
59418
|
updateTaskStatus,
|
|
59060
59419
|
upsertMeshMission,
|
|
59061
59420
|
upsertSavedProviderSession,
|
|
59421
|
+
validateChangeImpactConfig,
|
|
59062
59422
|
validateCliProviderManifest,
|
|
59063
59423
|
validateFsmSpec,
|
|
59064
59424
|
validateMeshRefineConfig,
|