@adhdev/daemon-core 0.9.82-rc.486 → 0.9.82-rc.488
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/commands/router-refine.d.ts +14 -0
- package/dist/git/git-status.d.ts +23 -0
- package/dist/index.js +232 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +232 -33
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-event-forwarding.d.ts +9 -0
- package/dist/mesh/mesh-refine-gates.d.ts +29 -0
- package/dist/mesh/mesh-work-queue.d.ts +11 -0
- package/dist/providers/cli-provider-instance.d.ts +1 -0
- package/dist/providers/provider-instance-manager.d.ts +1 -0
- package/dist/providers/provider-instance.d.ts +1 -0
- package/package.json +3 -3
- package/src/commands/cli-manager.ts +4 -0
- package/src/commands/router-refine.ts +87 -4
- package/src/git/git-status.ts +84 -29
- package/src/mesh/mesh-event-forwarding.ts +92 -0
- package/src/mesh/mesh-queue-assignment.ts +6 -0
- package/src/mesh/mesh-refine-gates.ts +113 -7
- package/src/mesh/mesh-runtime-store.ts +5 -0
- package/src/mesh/mesh-work-queue.ts +18 -0
- package/src/providers/cli-provider-instance.ts +17 -6
- package/src/providers/provider-instance-manager.ts +1 -1
- package/src/providers/provider-instance.ts +1 -1
package/dist/index.mjs
CHANGED
|
@@ -409,10 +409,10 @@ function readInjected(value) {
|
|
|
409
409
|
}
|
|
410
410
|
function getDaemonBuildInfo() {
|
|
411
411
|
if (cached) return cached;
|
|
412
|
-
const commit = readInjected(true ? "
|
|
413
|
-
const commitShort = readInjected(true ? "
|
|
414
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
415
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
412
|
+
const commit = readInjected(true ? "a659fcbbe9641240de42b95804a16b8852c5b4eb" : void 0) ?? "unknown";
|
|
413
|
+
const commitShort = readInjected(true ? "a659fcbb" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
414
|
+
const version = readInjected(true ? "0.9.82-rc.488" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
415
|
+
const builtAt = readInjected(true ? "2026-07-10T03:46:52.780Z" : void 0);
|
|
416
416
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
417
417
|
return cached;
|
|
418
418
|
}
|
|
@@ -784,30 +784,41 @@ function isNonRuntimeRootFile(file, policy) {
|
|
|
784
784
|
}
|
|
785
785
|
return false;
|
|
786
786
|
}
|
|
787
|
+
function classifyChangedFileList(files, policy) {
|
|
788
|
+
if (files.length === 0) {
|
|
789
|
+
return { isDaemonAffecting: true, affectedPackages: [] };
|
|
790
|
+
}
|
|
791
|
+
const pkgs = /* @__PURE__ */ new Set();
|
|
792
|
+
let sawRuntimeAmbiguousNonPackage = false;
|
|
793
|
+
for (const file of files) {
|
|
794
|
+
const match = file.match(/(?:^|\/)packages\/([^/]+)\//);
|
|
795
|
+
if (!match) {
|
|
796
|
+
if (!isNonRuntimeRootFile(file, policy)) sawRuntimeAmbiguousNonPackage = true;
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
799
|
+
pkgs.add(match[1]);
|
|
800
|
+
}
|
|
801
|
+
const affectedPackages = [...pkgs].sort();
|
|
802
|
+
const allBenign = !sawRuntimeAmbiguousNonPackage && affectedPackages.every((p) => policy.webOnlyPackages.has(p) && !policy.daemonRuntimePackages.has(p));
|
|
803
|
+
return { isDaemonAffecting: !allBenign, affectedPackages };
|
|
804
|
+
}
|
|
787
805
|
async function classifyDaemonBuildChange(repoPath, buildCommit, options, policy) {
|
|
788
806
|
try {
|
|
789
807
|
const diff = await runGit(repoPath, ["diff", "--name-only", `${buildCommit}..HEAD`], options);
|
|
790
808
|
const files = diff.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
791
|
-
|
|
792
|
-
return { isDaemonAffecting: true, affectedPackages: [] };
|
|
793
|
-
}
|
|
794
|
-
const pkgs = /* @__PURE__ */ new Set();
|
|
795
|
-
let sawRuntimeAmbiguousNonPackage = false;
|
|
796
|
-
for (const file of files) {
|
|
797
|
-
const match = file.match(/(?:^|\/)packages\/([^/]+)\//);
|
|
798
|
-
if (!match) {
|
|
799
|
-
if (!isNonRuntimeRootFile(file, policy)) sawRuntimeAmbiguousNonPackage = true;
|
|
800
|
-
continue;
|
|
801
|
-
}
|
|
802
|
-
pkgs.add(match[1]);
|
|
803
|
-
}
|
|
804
|
-
const affectedPackages = [...pkgs].sort();
|
|
805
|
-
const allBenign = !sawRuntimeAmbiguousNonPackage && affectedPackages.every((p) => policy.webOnlyPackages.has(p) && !policy.daemonRuntimePackages.has(p));
|
|
806
|
-
return { isDaemonAffecting: !allBenign, affectedPackages };
|
|
809
|
+
return classifyChangedFileList(files, policy);
|
|
807
810
|
} catch {
|
|
808
811
|
return { isDaemonAffecting: true, affectedPackages: [] };
|
|
809
812
|
}
|
|
810
813
|
}
|
|
814
|
+
async function classifyChangedPackages(repoPath, fromRef, toRef, options = {}) {
|
|
815
|
+
const repo = await resolveGitRepository(repoPath, options);
|
|
816
|
+
const { config } = resolveChangeImpactConfigForRepo(repo.repoRoot, options);
|
|
817
|
+
const policy = resolveChangeImpactPolicy(config);
|
|
818
|
+
const diff = await runGit(repoPath, ["diff", "--name-only", `${fromRef}..${toRef}`], options);
|
|
819
|
+
const files = diff.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
820
|
+
return classifyChangedFileList(files, policy);
|
|
821
|
+
}
|
|
811
822
|
function resolveChangeImpactConfigForRepo(repoRoot, options) {
|
|
812
823
|
if (options.changeImpactConfig === null) {
|
|
813
824
|
return { config: null, sourceKey: "forced-default" };
|
|
@@ -6158,6 +6169,7 @@ function reclaimStrandedAssignedTask(meshId, taskId, opts) {
|
|
|
6158
6169
|
delete entry.assignedSessionId;
|
|
6159
6170
|
delete entry.assignedProviderType;
|
|
6160
6171
|
delete entry.dispatchTimestamp;
|
|
6172
|
+
entry.dispatchNonce = (entry.dispatchNonce || 0) + 1;
|
|
6161
6173
|
entry.strandedReclaimCount = reclaims;
|
|
6162
6174
|
entry.updatedAt = now;
|
|
6163
6175
|
endTaskDispatchInFlight(meshId, taskId);
|
|
@@ -7181,6 +7193,7 @@ var init_mesh_runtime_store = __esm({
|
|
|
7181
7193
|
entry.assignedSessionId = sessionId;
|
|
7182
7194
|
if (providerType) entry.assignedProviderType = providerType;
|
|
7183
7195
|
entry.dispatchTimestamp = now;
|
|
7196
|
+
entry.dispatchNonce = (entry.dispatchNonce || 0) + 1;
|
|
7184
7197
|
entry.updatedAt = now;
|
|
7185
7198
|
this.db.prepare(`
|
|
7186
7199
|
UPDATE mesh_queue SET
|
|
@@ -15649,6 +15662,10 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
15649
15662
|
meshId,
|
|
15650
15663
|
nodeId,
|
|
15651
15664
|
taskId: task.id,
|
|
15665
|
+
// REDRIVE-DUP: carry the current dispatch nonce so the worker can echo it
|
|
15666
|
+
// back on generating_started; a reclaim bumps this row's nonce, making an
|
|
15667
|
+
// already-in-flight stale inject rejectable on arrival.
|
|
15668
|
+
...typeof task.dispatchNonce === "number" ? { dispatchNonce: task.dispatchNonce } : {},
|
|
15652
15669
|
...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {},
|
|
15653
15670
|
...sourceCoordinatorSessionId ? { coordinatorSessionId: sourceCoordinatorSessionId } : {}
|
|
15654
15671
|
}
|
|
@@ -15707,6 +15724,8 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
15707
15724
|
meshId,
|
|
15708
15725
|
nodeId,
|
|
15709
15726
|
taskId: task.id,
|
|
15727
|
+
// REDRIVE-DUP: carry the current dispatch nonce (see remote branch above).
|
|
15728
|
+
...typeof task.dispatchNonce === "number" ? { dispatchNonce: task.dispatchNonce } : {},
|
|
15710
15729
|
...localCoordinatorDaemonId() ? { coordinatorDaemonId: localCoordinatorDaemonId() } : {},
|
|
15711
15730
|
...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { coordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {}
|
|
15712
15731
|
}
|
|
@@ -19689,6 +19708,42 @@ function sourceWorkerAutoApproves(components, sessionId) {
|
|
|
19689
19708
|
return false;
|
|
19690
19709
|
}
|
|
19691
19710
|
}
|
|
19711
|
+
function stopStaleMeshWorker(components, args) {
|
|
19712
|
+
const { meshId, sessionId, providerType } = args;
|
|
19713
|
+
const stopArgs = {
|
|
19714
|
+
targetSessionId: sessionId,
|
|
19715
|
+
...providerType ? { cliType: providerType } : {},
|
|
19716
|
+
mode: "hard",
|
|
19717
|
+
reason: "stale_mesh_dispatch_reclaimed"
|
|
19718
|
+
};
|
|
19719
|
+
try {
|
|
19720
|
+
const isLocal = components.cliManager?.adapters?.has?.(sessionId) === true;
|
|
19721
|
+
if (isLocal) {
|
|
19722
|
+
if (!stopArgs.cliType) {
|
|
19723
|
+
const localType = components.cliManager?.adapters?.get?.(sessionId)?.cliType;
|
|
19724
|
+
if (localType) stopArgs.cliType = localType;
|
|
19725
|
+
}
|
|
19726
|
+
Promise.resolve(components.cliManager?.handleCliCommand?.("stop_cli", stopArgs)).catch((e) => LOG.warn("MeshQueue", `Local stop of stale worker ${sessionId} failed: ${e?.message || e}`));
|
|
19727
|
+
return;
|
|
19728
|
+
}
|
|
19729
|
+
let daemonId = args.daemonId;
|
|
19730
|
+
if (!daemonId && args.nodeId) {
|
|
19731
|
+
try {
|
|
19732
|
+
const mesh = getMeshWithCache(components, meshId);
|
|
19733
|
+
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, args.nodeId));
|
|
19734
|
+
daemonId = node ? readMeshNodeDaemonId(node) || void 0 : void 0;
|
|
19735
|
+
} catch {
|
|
19736
|
+
}
|
|
19737
|
+
}
|
|
19738
|
+
if (daemonId && components.dispatchMeshCommand) {
|
|
19739
|
+
Promise.resolve(components.dispatchMeshCommand(daemonId, "stop_cli", stopArgs)).catch((e) => LOG.warn("MeshQueue", `Remote stop of stale worker ${sessionId} on daemon ${daemonId} failed: ${e?.message || e}`));
|
|
19740
|
+
} else {
|
|
19741
|
+
LOG.warn("MeshQueue", `Cannot stop stale worker ${sessionId}: no local adapter and no resolvable remote daemon id (node ${args.nodeId ?? "?"}). Ack already rejected \u2014 task will re-strand-and-fail if the worker completes.`);
|
|
19742
|
+
}
|
|
19743
|
+
} catch (e) {
|
|
19744
|
+
LOG.warn("MeshQueue", `stopStaleMeshWorker error for ${sessionId}: ${e?.message || e}`);
|
|
19745
|
+
}
|
|
19746
|
+
}
|
|
19692
19747
|
function injectMeshSystemMessage(components, args) {
|
|
19693
19748
|
const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
19694
19749
|
const eventNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
@@ -19928,6 +19983,35 @@ function injectMeshSystemMessage(components, args) {
|
|
|
19928
19983
|
}
|
|
19929
19984
|
if (sessionId) {
|
|
19930
19985
|
const startedTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
|
|
19986
|
+
const startedNonce = typeof args.metadataEvent.dispatchNonce === "number" ? args.metadataEvent.dispatchNonce : void 0;
|
|
19987
|
+
if (startedTaskId && startedNonce !== void 0) {
|
|
19988
|
+
const currentRow = (() => {
|
|
19989
|
+
try {
|
|
19990
|
+
return MeshRuntimeStore.getInstance().findQueueEntryById(args.meshId, startedTaskId);
|
|
19991
|
+
} catch {
|
|
19992
|
+
return null;
|
|
19993
|
+
}
|
|
19994
|
+
})();
|
|
19995
|
+
const currentNonce = typeof currentRow?.dispatchNonce === "number" ? currentRow.dispatchNonce : void 0;
|
|
19996
|
+
if (currentNonce !== void 0 && startedNonce < currentNonce) {
|
|
19997
|
+
LOG.warn("MeshQueue", `Rejecting stale mesh dispatch: task ${startedTaskId} generating_started from session ${sessionId} (node ${nodeId ?? "?"}) carries dispatchNonce ${startedNonce} < current ${currentNonce} \u2014 the task was reclaimed and re-dispatched; stopping this worker to prevent duplicate execution.`);
|
|
19998
|
+
traceMeshEventDrop("stale_dispatch_nonce_rejected", {
|
|
19999
|
+
taskId: startedTaskId,
|
|
20000
|
+
sessionId,
|
|
20001
|
+
nodeId,
|
|
20002
|
+
meshId: args.meshId,
|
|
20003
|
+
event: "agent:generating_started"
|
|
20004
|
+
}, `nonce ${startedNonce} < ${currentNonce}`);
|
|
20005
|
+
stopStaleMeshWorker(components, {
|
|
20006
|
+
meshId: args.meshId,
|
|
20007
|
+
sessionId,
|
|
20008
|
+
nodeId,
|
|
20009
|
+
providerType: readNonEmptyString2(args.metadataEvent.providerType) || readNonEmptyString2(args.metadataEvent.cliType),
|
|
20010
|
+
daemonId: readNonEmptyString2(args.metadataEvent.sourceDaemonId) || readNonEmptyString2(args.metadataEvent.daemonId)
|
|
20011
|
+
});
|
|
20012
|
+
return { success: true, forwarded: 0, suppressed: true, staleDispatchRejected: true };
|
|
20013
|
+
}
|
|
20014
|
+
}
|
|
19931
20015
|
if (startedTaskId) {
|
|
19932
20016
|
updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
|
|
19933
20017
|
} else if (sessionHasActiveAssignment(args.meshId, sessionId)) {
|
|
@@ -20464,6 +20548,7 @@ var init_mesh_event_forwarding = __esm({
|
|
|
20464
20548
|
init_dist();
|
|
20465
20549
|
init_mesh_events_stale();
|
|
20466
20550
|
init_mesh_task_inflight();
|
|
20551
|
+
init_mesh_node_identity();
|
|
20467
20552
|
init_mesh_events_utils();
|
|
20468
20553
|
init_mesh_event_classify();
|
|
20469
20554
|
init_mesh_queue_assignment();
|
|
@@ -45546,6 +45631,10 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
45546
45631
|
// shares this daemon. See isMeshOwnedDelegateSession's post-detach gate.
|
|
45547
45632
|
...assignment.nodeId ? { meshNodeId: assignment.nodeId, meshLastNodeId: assignment.nodeId } : {},
|
|
45548
45633
|
...assignment.taskId ? { meshActiveTaskId: assignment.taskId } : {},
|
|
45634
|
+
// REDRIVE-DUP: task-level dispatch nonce, echoed on generating_started so the
|
|
45635
|
+
// coordinator can reject a stale (reclaimed) dispatch. Cleared with meshActiveTaskId
|
|
45636
|
+
// on detach so a subsequent unrelated turn never re-echoes a prior task's nonce.
|
|
45637
|
+
...typeof assignment.dispatchNonce === "number" ? { meshActiveDispatchNonce: assignment.dispatchNonce } : {},
|
|
45549
45638
|
...assignment.coordinatorDaemonId ? { meshCoordinatorDaemonId: assignment.coordinatorDaemonId } : {},
|
|
45550
45639
|
// Session-level routing anchor: the originating coordinator session, so this
|
|
45551
45640
|
// worker's completion events route back to the exact session that dispatched it.
|
|
@@ -45581,15 +45670,17 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
45581
45670
|
if (!this.settings.meshNodeFor && !this.settings.meshActiveTaskId && !this.settings.meshNodeId) return;
|
|
45582
45671
|
if (this.settings.launchedByCoordinator === true) {
|
|
45583
45672
|
if (!this.settings.meshActiveTaskId) return;
|
|
45584
|
-
const { meshActiveTaskId: meshActiveTaskId2, ...rest2 } = this.settings;
|
|
45673
|
+
const { meshActiveTaskId: meshActiveTaskId2, meshActiveDispatchNonce: meshActiveDispatchNonce2, ...rest2 } = this.settings;
|
|
45585
45674
|
void meshActiveTaskId2;
|
|
45675
|
+
void meshActiveDispatchNonce2;
|
|
45586
45676
|
this.settings = rest2;
|
|
45587
45677
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
45588
45678
|
return;
|
|
45589
45679
|
}
|
|
45590
|
-
const { meshNodeFor, meshNodeId, meshActiveTaskId, ...rest } = this.settings;
|
|
45680
|
+
const { meshNodeFor, meshNodeId, meshActiveTaskId, meshActiveDispatchNonce, ...rest } = this.settings;
|
|
45591
45681
|
void meshNodeFor;
|
|
45592
45682
|
void meshActiveTaskId;
|
|
45683
|
+
void meshActiveDispatchNonce;
|
|
45593
45684
|
const lastNodeId = typeof meshNodeId === "string" && meshNodeId.trim() ? meshNodeId.trim() : typeof rest.meshLastNodeId === "string" && rest.meshLastNodeId.trim() ? rest.meshLastNodeId.trim() : void 0;
|
|
45594
45685
|
this.settings = lastNodeId ? { ...rest, meshLastNodeId: lastNodeId } : rest;
|
|
45595
45686
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
@@ -47078,6 +47169,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
47078
47169
|
const resolved = this.completingTurnTaskId();
|
|
47079
47170
|
if (resolved) enrichedEvent.taskId = resolved;
|
|
47080
47171
|
}
|
|
47172
|
+
if (enrichedEvent.dispatchNonce === void 0 && typeof this.settings.meshActiveDispatchNonce === "number") {
|
|
47173
|
+
enrichedEvent.dispatchNonce = this.settings.meshActiveDispatchNonce;
|
|
47174
|
+
}
|
|
47081
47175
|
}
|
|
47082
47176
|
if (this.context?.emitProviderEvent) {
|
|
47083
47177
|
this.context.emitProviderEvent(enrichedEvent);
|
|
@@ -49969,6 +50063,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
49969
50063
|
meshId: meshContext.meshId,
|
|
49970
50064
|
...typeof meshContext.nodeId === "string" && meshContext.nodeId ? { nodeId: meshContext.nodeId } : {},
|
|
49971
50065
|
...typeof meshContext.taskId === "string" && meshContext.taskId ? { taskId: meshContext.taskId } : {},
|
|
50066
|
+
// REDRIVE-DUP: carry the dispatch nonce onto the worker session so
|
|
50067
|
+
// its generating_started event echoes it back for the coordinator's
|
|
50068
|
+
// stale-nonce guard.
|
|
50069
|
+
...typeof meshContext.dispatchNonce === "number" ? { dispatchNonce: meshContext.dispatchNonce } : {},
|
|
49972
50070
|
...typeof meshContext.coordinatorDaemonId === "string" && meshContext.coordinatorDaemonId ? { coordinatorDaemonId: meshContext.coordinatorDaemonId } : {}
|
|
49973
50071
|
});
|
|
49974
50072
|
} catch {
|
|
@@ -57804,6 +57902,7 @@ function orderMeshRefineBatchNodes(changeAreas) {
|
|
|
57804
57902
|
|
|
57805
57903
|
// src/commands/router-refine.ts
|
|
57806
57904
|
init_repo_mesh_types();
|
|
57905
|
+
init_git_status();
|
|
57807
57906
|
init_mesh_node_identity();
|
|
57808
57907
|
|
|
57809
57908
|
// src/mesh/mesh-refine-gates.ts
|
|
@@ -58744,6 +58843,41 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
58744
58843
|
if (fs31.existsSync(pathJoin2(cwd, "node_modules"))) return false;
|
|
58745
58844
|
return ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"].some((lock) => fs31.existsSync(pathJoin2(cwd, lock)));
|
|
58746
58845
|
};
|
|
58846
|
+
const needsNodeModules = (candidate, cwd) => isPackageManagerValidation(candidate) && dependenciesLikelyMissing(cwd);
|
|
58847
|
+
const isDaemonScopedCommand = (candidate) => {
|
|
58848
|
+
const haystack = [candidate.command, ...candidate.args || [], candidate.displayCommand || ""].join(" ").toLowerCase();
|
|
58849
|
+
if (candidate.category === "typecheck") return false;
|
|
58850
|
+
if (/\btypecheck\b/.test(haystack)) return false;
|
|
58851
|
+
if (/\bweb-core\b|\bweb-cloud\b|\bweb-standalone\b|\btest:web\b/.test(haystack)) return false;
|
|
58852
|
+
return /\bdaemon-core\b|\bdaemon-cloud\b|\btest:daemon\b|check-vendor-drift/.test(haystack);
|
|
58853
|
+
};
|
|
58854
|
+
const scopeUnaffectedDaemon = opts?.changeImpact?.isDaemonAffecting === false;
|
|
58855
|
+
const skippedDaemonCommands = [];
|
|
58856
|
+
const commandsToRun = [];
|
|
58857
|
+
for (const candidate of selection.commands) {
|
|
58858
|
+
if (scopeUnaffectedDaemon && isDaemonScopedCommand(candidate)) {
|
|
58859
|
+
skippedDaemonCommands.push(candidate.displayCommand);
|
|
58860
|
+
summary.commandsRun.push({
|
|
58861
|
+
command: candidate.command,
|
|
58862
|
+
args: candidate.args,
|
|
58863
|
+
displayCommand: candidate.displayCommand,
|
|
58864
|
+
category: candidate.category,
|
|
58865
|
+
source: candidate.source,
|
|
58866
|
+
passed: true,
|
|
58867
|
+
skipped: true,
|
|
58868
|
+
skipReason: "unaffected_daemon_scope"
|
|
58869
|
+
});
|
|
58870
|
+
continue;
|
|
58871
|
+
}
|
|
58872
|
+
commandsToRun.push(candidate);
|
|
58873
|
+
}
|
|
58874
|
+
if (opts?.changeImpact) {
|
|
58875
|
+
summary.changeImpact = {
|
|
58876
|
+
isDaemonAffecting: opts.changeImpact.isDaemonAffecting,
|
|
58877
|
+
affectedPackages: opts.changeImpact.affectedPackages,
|
|
58878
|
+
...skippedDaemonCommands.length ? { skippedDaemonCommands } : {}
|
|
58879
|
+
};
|
|
58880
|
+
}
|
|
58747
58881
|
if (runLegacyBootstrapCommands) {
|
|
58748
58882
|
summary.bootstrap = { stage: "legacy" };
|
|
58749
58883
|
for (const candidate of selection.bootstrapCommands) {
|
|
@@ -58778,23 +58912,22 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
58778
58912
|
}
|
|
58779
58913
|
}
|
|
58780
58914
|
}
|
|
58781
|
-
|
|
58915
|
+
let missingDepsBlocked = false;
|
|
58916
|
+
for (const candidate of commandsToRun) {
|
|
58782
58917
|
const startedAt = Date.now();
|
|
58783
58918
|
const cwd = candidate.cwd ? pathResolve2(workspace, candidate.cwd) : workspace;
|
|
58784
58919
|
const timeout = candidate.timeoutMs || REFINE_VALIDATION_TIMEOUT_MS;
|
|
58785
58920
|
const bootstrapProvidedDependencies = summary.bootstrap?.stage === "cached" || summary.bootstrap?.stage === "ran" || summary.bootstrap?.stage === "legacy";
|
|
58786
|
-
if (!bootstrapProvidedDependencies &&
|
|
58921
|
+
if (!bootstrapProvidedDependencies && needsNodeModules(candidate, cwd)) {
|
|
58787
58922
|
summary.commandsRun.push(commandRecord(candidate, cwd, startedAt, {
|
|
58788
|
-
stderr: "Dependencies appear to be missing: package.json and a lockfile are present, but node_modules is absent. Configure validation.bootstrapCommands in repo mesh/refine config if Refinery should install/bootstrap before validation."
|
|
58923
|
+
stderr: "Dependencies appear to be missing: package.json and a lockfile are present, but node_modules is absent. Configure validation.bootstrapCommands (or .adhdev/worktree_bootstrap.json) in repo mesh/refine config if Refinery should install/bootstrap before validation."
|
|
58789
58924
|
}, false, {
|
|
58790
58925
|
exitCode: null,
|
|
58791
58926
|
skipped: true,
|
|
58792
58927
|
failureKind: "missing_dependencies"
|
|
58793
58928
|
}));
|
|
58794
|
-
|
|
58795
|
-
|
|
58796
|
-
summary.failureCode = "missing_dependencies";
|
|
58797
|
-
return summary;
|
|
58929
|
+
missingDepsBlocked = true;
|
|
58930
|
+
continue;
|
|
58798
58931
|
}
|
|
58799
58932
|
const resolvedCommand = resolveWin32Executable(candidate.command);
|
|
58800
58933
|
const spawn5 = buildWin32ExecFileSpawn(resolvedCommand, candidate.args);
|
|
@@ -58830,6 +58963,12 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
58830
58963
|
return summary;
|
|
58831
58964
|
}
|
|
58832
58965
|
}
|
|
58966
|
+
if (missingDepsBlocked) {
|
|
58967
|
+
summary.status = "failed";
|
|
58968
|
+
summary.failureKind = "missing_dependencies";
|
|
58969
|
+
summary.failureCode = "missing_dependencies";
|
|
58970
|
+
return summary;
|
|
58971
|
+
}
|
|
58833
58972
|
summary.status = "passed";
|
|
58834
58973
|
return summary;
|
|
58835
58974
|
}
|
|
@@ -58862,7 +59001,50 @@ function buildRefineJobHandle(self, args) {
|
|
|
58862
59001
|
}
|
|
58863
59002
|
};
|
|
58864
59003
|
}
|
|
59004
|
+
function slimRefineEventResult(result) {
|
|
59005
|
+
const slim = {};
|
|
59006
|
+
for (const key2 of [
|
|
59007
|
+
"success",
|
|
59008
|
+
"code",
|
|
59009
|
+
"error",
|
|
59010
|
+
"convergenceStatus",
|
|
59011
|
+
"blockedReason",
|
|
59012
|
+
"branch",
|
|
59013
|
+
"into",
|
|
59014
|
+
"terminalKind",
|
|
59015
|
+
"nextStep",
|
|
59016
|
+
"finalBranchConvergenceState"
|
|
59017
|
+
]) {
|
|
59018
|
+
if (result[key2] !== void 0) slim[key2] = result[key2];
|
|
59019
|
+
}
|
|
59020
|
+
if (Array.isArray(result.unreachableSubmoduleCommits)) {
|
|
59021
|
+
slim.unreachableSubmoduleCommits = result.unreachableSubmoduleCommits.map((e) => ({ path: e?.path, autoPublishAllowed: e?.autoPublishAllowed }));
|
|
59022
|
+
}
|
|
59023
|
+
if (result.validationSummary && typeof result.validationSummary === "object") {
|
|
59024
|
+
const vs = result.validationSummary;
|
|
59025
|
+
slim.validationSummary = {
|
|
59026
|
+
status: vs.status,
|
|
59027
|
+
failureCode: vs.failureCode,
|
|
59028
|
+
configSource: vs.configSource,
|
|
59029
|
+
configSourceType: vs.configSourceType,
|
|
59030
|
+
commandsRunCount: Array.isArray(vs.commandsRun) ? vs.commandsRun.length : void 0
|
|
59031
|
+
};
|
|
59032
|
+
}
|
|
59033
|
+
if (result.patchEquivalence && typeof result.patchEquivalence === "object") {
|
|
59034
|
+
const pe = result.patchEquivalence;
|
|
59035
|
+
slim.patchEquivalence = { status: pe.status, equivalent: pe.equivalent };
|
|
59036
|
+
}
|
|
59037
|
+
if (result.submoduleReachability && typeof result.submoduleReachability === "object") {
|
|
59038
|
+
const sr = result.submoduleReachability;
|
|
59039
|
+
slim.submoduleReachability = {
|
|
59040
|
+
checked: Array.isArray(sr.entries) ? sr.entries.length : void 0,
|
|
59041
|
+
unreachable: Array.isArray(sr.unreachable) ? sr.unreachable.length : void 0
|
|
59042
|
+
};
|
|
59043
|
+
}
|
|
59044
|
+
return slim;
|
|
59045
|
+
}
|
|
58865
59046
|
function queueRefineJobEvent(self, event, handle, result) {
|
|
59047
|
+
const slimResult = result ? slimRefineEventResult(result) : void 0;
|
|
58866
59048
|
const metadataEvent = {
|
|
58867
59049
|
source: "refine_mesh_node_async_job",
|
|
58868
59050
|
jobId: handle.jobId,
|
|
@@ -58875,7 +59057,7 @@ function queueRefineJobEvent(self, event, handle, result) {
|
|
|
58875
59057
|
startedAt: handle.startedAt,
|
|
58876
59058
|
completedAt: handle.completedAt,
|
|
58877
59059
|
retryOfJobId: handle.retryOfJobId,
|
|
58878
|
-
...
|
|
59060
|
+
...slimResult ? { result: slimResult } : {}
|
|
58879
59061
|
};
|
|
58880
59062
|
const eventPayload = {
|
|
58881
59063
|
event,
|
|
@@ -58902,7 +59084,7 @@ function queueRefineJobEvent(self, event, handle, result) {
|
|
|
58902
59084
|
startedAt: handle.startedAt,
|
|
58903
59085
|
completedAt: handle.completedAt,
|
|
58904
59086
|
retryOfJobId: handle.retryOfJobId,
|
|
58905
|
-
...
|
|
59087
|
+
...slimResult ? { result: slimResult } : {}
|
|
58906
59088
|
}
|
|
58907
59089
|
);
|
|
58908
59090
|
if (forwarded?.success === true) return;
|
|
@@ -59037,7 +59219,20 @@ async function refineResolveRefsStage(self, meshId, nodeId, args, refineStages)
|
|
|
59037
59219
|
const { stdout: branchHeadStdout } = await execFileAsync4("git", ["rev-parse", branch], { cwd: node.workspace, encoding: "utf8" });
|
|
59038
59220
|
const baseHead = baseHeadRaw;
|
|
59039
59221
|
const branchHead = branchHeadStdout.trim();
|
|
59040
|
-
|
|
59222
|
+
let changeImpact;
|
|
59223
|
+
try {
|
|
59224
|
+
changeImpact = await classifyChangedPackages(node.workspace, baseHead, branchHead);
|
|
59225
|
+
} catch {
|
|
59226
|
+
changeImpact = void 0;
|
|
59227
|
+
}
|
|
59228
|
+
recordMeshRefineStage(refineStages, "resolve_refs", "passed", resolveStarted, {
|
|
59229
|
+
branch,
|
|
59230
|
+
baseBranch,
|
|
59231
|
+
baseHead,
|
|
59232
|
+
branchHead,
|
|
59233
|
+
...changeImpact ? { changeImpact } : {},
|
|
59234
|
+
...fetchWarning ? { fetchWarning } : {}
|
|
59235
|
+
});
|
|
59041
59236
|
return {
|
|
59042
59237
|
kind: "continue",
|
|
59043
59238
|
ctx: {
|
|
@@ -59054,6 +59249,7 @@ async function refineResolveRefsStage(self, meshId, nodeId, args, refineStages)
|
|
|
59054
59249
|
baseBranch,
|
|
59055
59250
|
baseHead,
|
|
59056
59251
|
branchHead,
|
|
59252
|
+
changeImpact,
|
|
59057
59253
|
validationSummary: void 0,
|
|
59058
59254
|
patchEquivalence: void 0,
|
|
59059
59255
|
submoduleReachability: void 0
|
|
@@ -59064,6 +59260,9 @@ async function refineValidationStage(self, ctx) {
|
|
|
59064
59260
|
const { mesh, node, branch, baseBranch, refineStages } = ctx;
|
|
59065
59261
|
const validationStarted = Date.now();
|
|
59066
59262
|
const validationSummary = await runMeshRefineValidationGate(mesh, node.workspace, {
|
|
59263
|
+
// (a) Scope the validation command set by coarse change-impact (resolved
|
|
59264
|
+
// in resolve_refs). Undefined → gate runs the full command set (fail-open).
|
|
59265
|
+
changeImpact: ctx.changeImpact,
|
|
59067
59266
|
// M2-2: consume the node's persisted bootstrap state; persist re-runs.
|
|
59068
59267
|
persistedBootstrapState: node.worktreeBootstrap,
|
|
59069
59268
|
onBootstrapStateChange: (state) => {
|
|
@@ -59083,7 +59282,7 @@ async function refineValidationStage(self, ctx) {
|
|
|
59083
59282
|
if (validationSummary.status === "failed") {
|
|
59084
59283
|
const firstFailedCmd = Array.isArray(validationSummary.commandsRun) ? validationSummary.commandsRun.find((c) => c.success === false) : void 0;
|
|
59085
59284
|
const buildValidationFailedError = () => {
|
|
59086
|
-
const base = validationSummary.failureCode === "missing_dependencies" ? "Refinery validation dependencies are missing; merge/refine was not attempted.
|
|
59285
|
+
const base = validationSummary.failureCode === "missing_dependencies" ? "Refinery validation dependencies are missing for a change-affected package; merge/refine was not attempted. To make this self-service, either (1) configure .adhdev/worktree_bootstrap.json (or validation.bootstrapCommands in .adhdev/refine.json) so Refinery installs deps before validation, or (2) converge the branch via the documented manual fast-forward-only bypass (rebase onto the fetched base, verify strict ancestry, then push ff-only) instead of the refine gate." : validationSummary.failureCode === "dependency_bootstrap_failed" ? "Refinery dependency/bootstrap command failed; merge/refine was not attempted." : validationSummary.failureCode === "spawn_resolution_failed" ? validationSummary.spawnResolutionError || "Refinery validation command could not be spawned (executable not found); merge/refine was not attempted." : "Refinery validation gate failed; merge/refine was not attempted.";
|
|
59087
59286
|
if (!firstFailedCmd) return base;
|
|
59088
59287
|
const cmdName = typeof firstFailedCmd.displayCommand === "string" ? firstFailedCmd.displayCommand : typeof firstFailedCmd.command === "string" ? [firstFailedCmd.command, ...Array.isArray(firstFailedCmd.args) ? firstFailedCmd.args : []].join(" ").trim() : typeof firstFailedCmd.cmd === "string" ? firstFailedCmd.cmd : "";
|
|
59089
59288
|
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s2) => typeof s2 === "string" && s2.length > 0).join("\n");
|