@adhdev/daemon-core 0.9.82-rc.64 → 0.9.82-rc.66

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.64",
3
+ "version": "0.9.82-rc.66",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -166,6 +166,7 @@ function summarizeRepoMeshStatusDebug(status: any): Record<string, unknown> {
166
166
  meshId: readStringValue(status?.meshId, status?.mesh_id) ?? null,
167
167
  refreshedAt: readStringValue(status?.refreshedAt, status?.refreshed_at) ?? null,
168
168
  sourceOfTruth: status?.sourceOfTruth ?? null,
169
+ branchConvergenceSummary: status?.branchConvergenceSummary ?? status?.branch_convergence_summary ?? null,
169
170
  nodeCount: nodes.length,
170
171
  nodes: nodes.map((node: any) => ({
171
172
  nodeId: readStringValue(node?.nodeId, node?.id) ?? null,
@@ -182,6 +183,7 @@ function summarizeRepoMeshStatusDebug(status: any): Record<string, unknown> {
182
183
  gitProbePending: node?.gitProbePending === true,
183
184
  launchReady: node?.launchReady === true,
184
185
  git: summarizeRepoMeshDebugGit(node?.git),
186
+ branchConvergence: node?.branchConvergence ?? node?.branch_convergence ?? null,
185
187
  })),
186
188
  };
187
189
  }
@@ -793,7 +795,7 @@ async function probeRemoteMeshGitStatus(args: {
793
795
  }): Promise<Record<string, unknown> | null> {
794
796
  if (!args.dispatchMeshCommand) return null;
795
797
  const remoteResult = await Promise.race([
796
- args.dispatchMeshCommand(args.daemonId, 'git_status', { workspace: args.workspace }),
798
+ args.dispatchMeshCommand(args.daemonId, 'git_status', { workspace: args.workspace, refreshUpstream: true }),
797
799
  new Promise<never>((_, reject) => setTimeout(() => reject(new Error('timeout')), args.timeoutMs)),
798
800
  ]) as any;
799
801
  const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
@@ -1082,6 +1084,24 @@ type MeshRefinePatchEquivalenceSummary = {
1082
1084
  stderr?: string;
1083
1085
  };
1084
1086
 
1087
+ type MeshRefineSubmoduleReachabilityEntry = {
1088
+ path: string;
1089
+ commit: string;
1090
+ reachable: boolean;
1091
+ checkedLocal?: boolean;
1092
+ fetchedFromOrigin?: boolean;
1093
+ error?: string;
1094
+ };
1095
+
1096
+ type MeshRefineSubmoduleReachabilitySummary = {
1097
+ status: MeshRefineStageStatus;
1098
+ checked: number;
1099
+ unreachable: MeshRefineSubmoduleReachabilityEntry[];
1100
+ entries: MeshRefineSubmoduleReachabilityEntry[];
1101
+ durationMs: number;
1102
+ error?: string;
1103
+ };
1104
+
1085
1105
  type MeshRefineAsyncJobStatus = 'accepted' | 'completed' | 'failed';
1086
1106
 
1087
1107
  type MeshRefineJobHandle = {
@@ -1214,6 +1234,95 @@ async function runMeshRefinePatchEquivalenceGate(
1214
1234
  }
1215
1235
  }
1216
1236
 
1237
+ async function runMeshRefineSubmoduleReachabilityGate(
1238
+ repoRoot: string,
1239
+ mergedTree: string,
1240
+ ): Promise<MeshRefineSubmoduleReachabilitySummary> {
1241
+ const startedAt = Date.now();
1242
+ const entries: MeshRefineSubmoduleReachabilityEntry[] = [];
1243
+ try {
1244
+ const { execFile } = await import('node:child_process');
1245
+ const { promisify } = await import('node:util');
1246
+ const execFileAsync = promisify(execFile);
1247
+ const runGit = async (cwd: string, args: string[]): Promise<string> => {
1248
+ const { stdout } = await execFileAsync('git', args, {
1249
+ cwd,
1250
+ encoding: 'utf8',
1251
+ timeout: 30_000,
1252
+ maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES,
1253
+ windowsHide: true,
1254
+ });
1255
+ return String(stdout || '');
1256
+ };
1257
+
1258
+ const treeOutput = await runGit(repoRoot, ['ls-tree', '-r', '-z', mergedTree]);
1259
+ const gitlinks = treeOutput
1260
+ .split('\0')
1261
+ .filter(Boolean)
1262
+ .map(record => {
1263
+ const match = /^160000\s+commit\s+([0-9a-f]{40})\t(.+)$/.exec(record);
1264
+ return match ? { commit: match[1], path: match[2] } : null;
1265
+ })
1266
+ .filter((entry): entry is { commit: string; path: string } => !!entry);
1267
+
1268
+ for (const gitlink of gitlinks) {
1269
+ const submodulePath = pathResolve(repoRoot, gitlink.path);
1270
+ const entry: MeshRefineSubmoduleReachabilityEntry = {
1271
+ path: gitlink.path,
1272
+ commit: gitlink.commit,
1273
+ reachable: false,
1274
+ };
1275
+ try {
1276
+ if (!fs.existsSync(submodulePath)) {
1277
+ entry.error = `Submodule checkout missing at ${gitlink.path}`;
1278
+ entries.push(entry);
1279
+ continue;
1280
+ }
1281
+
1282
+ entry.checkedLocal = true;
1283
+ try {
1284
+ await runGit(submodulePath, ['cat-file', '-e', `${gitlink.commit}^{commit}`]);
1285
+ entry.reachable = true;
1286
+ entries.push(entry);
1287
+ continue;
1288
+ } catch {
1289
+ // Probe the submodule remote before allowing cleanup/completion.
1290
+ }
1291
+
1292
+ try {
1293
+ await runGit(submodulePath, ['fetch', 'origin', gitlink.commit]);
1294
+ entry.fetchedFromOrigin = true;
1295
+ await runGit(submodulePath, ['cat-file', '-e', `${gitlink.commit}^{commit}`]);
1296
+ entry.reachable = true;
1297
+ } catch (e: any) {
1298
+ entry.error = truncateValidationOutput(e?.stderr || e?.message || String(e));
1299
+ }
1300
+ } catch (e: any) {
1301
+ entry.error = truncateValidationOutput(e?.message || String(e));
1302
+ }
1303
+ entries.push(entry);
1304
+ }
1305
+
1306
+ const unreachable = entries.filter(entry => !entry.reachable);
1307
+ return {
1308
+ status: unreachable.length ? 'failed' : 'passed',
1309
+ checked: entries.length,
1310
+ unreachable,
1311
+ entries,
1312
+ durationMs: Date.now() - startedAt,
1313
+ };
1314
+ } catch (e: any) {
1315
+ return {
1316
+ status: 'failed',
1317
+ checked: entries.length,
1318
+ unreachable: entries.filter(entry => !entry.reachable),
1319
+ entries,
1320
+ durationMs: Date.now() - startedAt,
1321
+ error: truncateValidationOutput(e?.message || String(e)),
1322
+ };
1323
+ }
1324
+ }
1325
+
1217
1326
  function buildMeshRefineValidationPlan(mesh: any, workspace: string): Record<string, unknown> {
1218
1327
  const plan = resolveMeshRefineValidationPlan(mesh, workspace);
1219
1328
  return {
@@ -2564,6 +2673,38 @@ export class DaemonCommandRouter {
2564
2673
  };
2565
2674
  }
2566
2675
 
2676
+ const submoduleReachabilityStarted = Date.now();
2677
+ const submoduleReachability = await runMeshRefineSubmoduleReachabilityGate(repoRoot, patchEquivalence.mergedTree || branchHead);
2678
+ recordMeshRefineStage(refineStages, 'submodule_reachability', submoduleReachability.status, submoduleReachabilityStarted, {
2679
+ checked: submoduleReachability.checked,
2680
+ unreachable: submoduleReachability.unreachable.map(entry => ({ path: entry.path, commit: entry.commit, error: entry.error })),
2681
+ error: submoduleReachability.error,
2682
+ });
2683
+ if (submoduleReachability.status === 'failed') {
2684
+ return {
2685
+ success: false,
2686
+ code: 'submodule_reachability_failed',
2687
+ convergenceStatus: 'blocked_review',
2688
+ error: 'Refinery submodule reachability preflight failed; merge/refine cleanup was not attempted.',
2689
+ branch,
2690
+ into: baseBranch,
2691
+ validationSummary,
2692
+ patchEquivalence,
2693
+ submoduleReachability,
2694
+ refineStages,
2695
+ finalBranchConvergenceState: {
2696
+ branch,
2697
+ baseBranch,
2698
+ merged: false,
2699
+ removed: false,
2700
+ validation: 'passed',
2701
+ patchEquivalence: 'passed',
2702
+ submoduleReachability: 'failed',
2703
+ status: 'blocked_review',
2704
+ },
2705
+ };
2706
+ }
2707
+
2567
2708
  let mergeResult: Record<string, unknown> | undefined;
2568
2709
  const mergeStarted = Date.now();
2569
2710
  try {