@ricsam/r5d-worker 0.0.104 → 0.0.105

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/cjs/main.cjs CHANGED
@@ -3986,6 +3986,7 @@ async function startWorker(options) {
3986
3986
  )
3987
3987
  ].sort();
3988
3988
  const ensureConfiguredProjects = async (onProgress) => {
3989
+ const reconciledProjectIds = /* @__PURE__ */ new Set();
3989
3990
  const projects = [...projectConfigById.values()];
3990
3991
  for (const [projectIndex, project] of projects.entries()) {
3991
3992
  onProgress?.({
@@ -4051,6 +4052,7 @@ async function startWorker(options) {
4051
4052
  });
4052
4053
  readyProjectIds.add(project.projectId);
4053
4054
  reconciledProjectConfigFingerprints.set(project.projectId, configFingerprint);
4055
+ reconciledProjectIds.add(project.projectId);
4054
4056
  for (const state of states) {
4055
4057
  pendingCheckouts.delete(projectBranchKey(project.projectId, state.branchName));
4056
4058
  const key = projectBranchKey(project.projectId, state.branchName);
@@ -4088,26 +4090,37 @@ async function startWorker(options) {
4088
4090
  totalItems: projects.length
4089
4091
  });
4090
4092
  }
4093
+ return reconciledProjectIds;
4091
4094
  };
4092
- const collectAheadOfOriginBranches = async () => {
4095
+ const ORIGIN_DIVERGENCE_REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
4096
+ const lastOriginDivergenceFetchMs = /* @__PURE__ */ new Map();
4097
+ const collectAheadOfOriginBranches = async (refetchOriginProjectIds) => {
4093
4098
  const aheadBranches = [];
4099
+ for (const projectId of [...lastOriginDivergenceFetchMs.keys()]) {
4100
+ if (!projectConfigById.has(projectId)) lastOriginDivergenceFetchMs.delete(projectId);
4101
+ }
4094
4102
  for (const project of projectConfigById.values()) {
4095
4103
  if (project.executionDisabled || !readyProjectIds.has(project.projectId) || project.branches.length === 0) continue;
4096
4104
  const connection = projectConnection(project);
4097
4105
  const primaryPath = configuredProjectBranchPath(projectsRoot, project, primaryProjectBranch(project));
4098
- if (!await tryGitAsync(
4099
- [
4100
- ...(0, import_git_process_environment.gitTransportSecurityArgs)(connection.originUrl, connection.credentialHelper, connection.originCredentialUsername),
4101
- "fetch",
4102
- "--no-recurse-submodules",
4103
- "--prune",
4104
- "origin",
4105
- "+refs/heads/*:refs/remotes/origin/*"
4106
- ],
4107
- { cwd: primaryPath }
4108
- )) {
4109
- process.stderr.write(`[r5d-worker] could not refresh origin divergence for ${project.projectPath}
4106
+ const lastFetchedAtMs = lastOriginDivergenceFetchMs.get(project.projectId);
4107
+ if (refetchOriginProjectIds.has(project.projectId) || lastFetchedAtMs === void 0 || Date.now() - lastFetchedAtMs >= ORIGIN_DIVERGENCE_REFRESH_INTERVAL_MS) {
4108
+ if (await tryGitAsync(
4109
+ [
4110
+ ...(0, import_git_process_environment.gitTransportSecurityArgs)(connection.originUrl, connection.credentialHelper, connection.originCredentialUsername),
4111
+ "fetch",
4112
+ "--no-recurse-submodules",
4113
+ "--prune",
4114
+ "origin",
4115
+ "+refs/heads/*:refs/remotes/origin/*"
4116
+ ],
4117
+ { cwd: primaryPath }
4118
+ )) {
4119
+ lastOriginDivergenceFetchMs.set(project.projectId, Date.now());
4120
+ } else {
4121
+ process.stderr.write(`[r5d-worker] could not refresh origin divergence for ${project.projectPath}
4110
4122
  `);
4123
+ }
4111
4124
  }
4112
4125
  for (const branch of project.branches) {
4113
4126
  const branchPath = configuredProjectBranchPath(projectsRoot, project, branch.branchName);
@@ -5238,7 +5251,7 @@ async function startWorker(options) {
5238
5251
  // checkout initialization from erasing synchronized dirt.
5239
5252
  { ignoreBusy: true, hydrationHooks: workspaceHydrationTransactionHooks }
5240
5253
  );
5241
- await ensureConfiguredProjects((progress) => {
5254
+ const reconciledProjectIds = await ensureConfiguredProjects((progress) => {
5242
5255
  sendLifecycleProgress({ phase: "configuring", operationId: configurationOperationId, ...progress });
5243
5256
  process.stdout.write(
5244
5257
  `[r5d-worker] ${progress.detail ?? "Configuring workspace"}${progress.completedBytes === void 0 ? "" : `: ${progress.completedBytes}/${progress.totalBytes ?? "?"} bytes`}${progress.completedItems === void 0 ? "" : `, ${progress.completedItems}/${progress.totalItems ?? "?"} item(s)`}
@@ -5294,7 +5307,7 @@ async function startWorker(options) {
5294
5307
  const pending = [...pendingCheckouts.values()].sort(
5295
5308
  (left, right) => left.projectId.localeCompare(right.projectId) || left.branchName.localeCompare(right.branchName)
5296
5309
  );
5297
- return { result, pending, aheadOfOriginBranches: await collectAheadOfOriginBranches() };
5310
+ return { result, pending, aheadOfOriginBranches: await collectAheadOfOriginBranches(reconciledProjectIds) };
5298
5311
  });
5299
5312
  } catch (error) {
5300
5313
  if (receiptGeneration !== workspaceConfigurationReceiptGeneration) {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5d-worker",
3
- "version": "0.0.104",
3
+ "version": "0.0.105",
4
4
  "type": "commonjs"
5
5
  }
@@ -1006,11 +1006,12 @@ async function reconcileLinkedLayout(input) {
1006
1006
  const plan = [];
1007
1007
  for (const branch of input.branches) {
1008
1008
  const checkoutPath = branchPath(input.projectRoot, branch.branchName);
1009
+ const exactMirror = input.exactMirrorBranches?.has(branch.branchName) === true;
1009
1010
  const resolved = await seedForBranch({
1010
1011
  ...input,
1011
1012
  primaryPath,
1012
1013
  branch,
1013
- requireMirrorHead: input.exactMirrorBranches?.has(branch.branchName)
1014
+ requireMirrorHead: exactMirror
1014
1015
  });
1015
1016
  mirrorHeads.set(branch.branchName, resolved.mirrorHead);
1016
1017
  const linked = branch.branchName === input.primaryBranchName || gitDirectoryKind(checkoutPath) !== null && await commonGitDirectoryAsync(checkoutPath) === primaryCommonDir;
@@ -1019,7 +1020,8 @@ async function reconcileLinkedLayout(input) {
1019
1020
  continue;
1020
1021
  }
1021
1022
  const currentHead = await gitAsync(checkoutPath, ["rev-parse", "HEAD"], `resolve linked worktree head ${branch.branchName}`);
1022
- plan.push({ branchName: branch.branchName, checkoutPath, seed: resolved.seed, action: currentHead === resolved.seed ? "keep" : "reset" });
1023
+ const keep = currentHead === resolved.seed || !exactMirror && await tryGitAsync(checkoutPath, ["merge-base", "--is-ancestor", resolved.seed, currentHead]);
1024
+ plan.push({ branchName: branch.branchName, checkoutPath, seed: resolved.seed, action: keep ? "keep" : "reset" });
1023
1025
  }
1024
1026
  const mutatedBranches = new Set(plan.filter(({ action }) => action !== "keep").map(({ branchName }) => branchName));
1025
1027
  if (mutatedBranches.size > 0) input.beforeDestructiveMutation(mutatedBranches);
package/dist/mjs/main.mjs CHANGED
@@ -3997,6 +3997,7 @@ async function startWorker(options) {
3997
3997
  )
3998
3998
  ].sort();
3999
3999
  const ensureConfiguredProjects = async (onProgress) => {
4000
+ const reconciledProjectIds = /* @__PURE__ */ new Set();
4000
4001
  const projects = [...projectConfigById.values()];
4001
4002
  for (const [projectIndex, project] of projects.entries()) {
4002
4003
  onProgress?.({
@@ -4062,6 +4063,7 @@ async function startWorker(options) {
4062
4063
  });
4063
4064
  readyProjectIds.add(project.projectId);
4064
4065
  reconciledProjectConfigFingerprints.set(project.projectId, configFingerprint);
4066
+ reconciledProjectIds.add(project.projectId);
4065
4067
  for (const state of states) {
4066
4068
  pendingCheckouts.delete(projectBranchKey(project.projectId, state.branchName));
4067
4069
  const key = projectBranchKey(project.projectId, state.branchName);
@@ -4099,26 +4101,37 @@ async function startWorker(options) {
4099
4101
  totalItems: projects.length
4100
4102
  });
4101
4103
  }
4104
+ return reconciledProjectIds;
4102
4105
  };
4103
- const collectAheadOfOriginBranches = async () => {
4106
+ const ORIGIN_DIVERGENCE_REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
4107
+ const lastOriginDivergenceFetchMs = /* @__PURE__ */ new Map();
4108
+ const collectAheadOfOriginBranches = async (refetchOriginProjectIds) => {
4104
4109
  const aheadBranches = [];
4110
+ for (const projectId of [...lastOriginDivergenceFetchMs.keys()]) {
4111
+ if (!projectConfigById.has(projectId)) lastOriginDivergenceFetchMs.delete(projectId);
4112
+ }
4105
4113
  for (const project of projectConfigById.values()) {
4106
4114
  if (project.executionDisabled || !readyProjectIds.has(project.projectId) || project.branches.length === 0) continue;
4107
4115
  const connection = projectConnection(project);
4108
4116
  const primaryPath = configuredProjectBranchPath(projectsRoot, project, primaryProjectBranch(project));
4109
- if (!await tryGitAsync(
4110
- [
4111
- ...gitTransportSecurityArgs(connection.originUrl, connection.credentialHelper, connection.originCredentialUsername),
4112
- "fetch",
4113
- "--no-recurse-submodules",
4114
- "--prune",
4115
- "origin",
4116
- "+refs/heads/*:refs/remotes/origin/*"
4117
- ],
4118
- { cwd: primaryPath }
4119
- )) {
4120
- process.stderr.write(`[r5d-worker] could not refresh origin divergence for ${project.projectPath}
4117
+ const lastFetchedAtMs = lastOriginDivergenceFetchMs.get(project.projectId);
4118
+ if (refetchOriginProjectIds.has(project.projectId) || lastFetchedAtMs === void 0 || Date.now() - lastFetchedAtMs >= ORIGIN_DIVERGENCE_REFRESH_INTERVAL_MS) {
4119
+ if (await tryGitAsync(
4120
+ [
4121
+ ...gitTransportSecurityArgs(connection.originUrl, connection.credentialHelper, connection.originCredentialUsername),
4122
+ "fetch",
4123
+ "--no-recurse-submodules",
4124
+ "--prune",
4125
+ "origin",
4126
+ "+refs/heads/*:refs/remotes/origin/*"
4127
+ ],
4128
+ { cwd: primaryPath }
4129
+ )) {
4130
+ lastOriginDivergenceFetchMs.set(project.projectId, Date.now());
4131
+ } else {
4132
+ process.stderr.write(`[r5d-worker] could not refresh origin divergence for ${project.projectPath}
4121
4133
  `);
4134
+ }
4122
4135
  }
4123
4136
  for (const branch of project.branches) {
4124
4137
  const branchPath = configuredProjectBranchPath(projectsRoot, project, branch.branchName);
@@ -5249,7 +5262,7 @@ async function startWorker(options) {
5249
5262
  // checkout initialization from erasing synchronized dirt.
5250
5263
  { ignoreBusy: true, hydrationHooks: workspaceHydrationTransactionHooks }
5251
5264
  );
5252
- await ensureConfiguredProjects((progress) => {
5265
+ const reconciledProjectIds = await ensureConfiguredProjects((progress) => {
5253
5266
  sendLifecycleProgress({ phase: "configuring", operationId: configurationOperationId, ...progress });
5254
5267
  process.stdout.write(
5255
5268
  `[r5d-worker] ${progress.detail ?? "Configuring workspace"}${progress.completedBytes === void 0 ? "" : `: ${progress.completedBytes}/${progress.totalBytes ?? "?"} bytes`}${progress.completedItems === void 0 ? "" : `, ${progress.completedItems}/${progress.totalItems ?? "?"} item(s)`}
@@ -5305,7 +5318,7 @@ async function startWorker(options) {
5305
5318
  const pending = [...pendingCheckouts.values()].sort(
5306
5319
  (left, right) => left.projectId.localeCompare(right.projectId) || left.branchName.localeCompare(right.branchName)
5307
5320
  );
5308
- return { result, pending, aheadOfOriginBranches: await collectAheadOfOriginBranches() };
5321
+ return { result, pending, aheadOfOriginBranches: await collectAheadOfOriginBranches(reconciledProjectIds) };
5309
5322
  });
5310
5323
  } catch (error) {
5311
5324
  if (receiptGeneration !== workspaceConfigurationReceiptGeneration) {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5d-worker",
3
- "version": "0.0.104",
3
+ "version": "0.0.105",
4
4
  "type": "module"
5
5
  }
@@ -956,11 +956,12 @@ async function reconcileLinkedLayout(input) {
956
956
  const plan = [];
957
957
  for (const branch of input.branches) {
958
958
  const checkoutPath = branchPath(input.projectRoot, branch.branchName);
959
+ const exactMirror = input.exactMirrorBranches?.has(branch.branchName) === true;
959
960
  const resolved = await seedForBranch({
960
961
  ...input,
961
962
  primaryPath,
962
963
  branch,
963
- requireMirrorHead: input.exactMirrorBranches?.has(branch.branchName)
964
+ requireMirrorHead: exactMirror
964
965
  });
965
966
  mirrorHeads.set(branch.branchName, resolved.mirrorHead);
966
967
  const linked = branch.branchName === input.primaryBranchName || gitDirectoryKind(checkoutPath) !== null && await commonGitDirectoryAsync(checkoutPath) === primaryCommonDir;
@@ -969,7 +970,8 @@ async function reconcileLinkedLayout(input) {
969
970
  continue;
970
971
  }
971
972
  const currentHead = await gitAsync(checkoutPath, ["rev-parse", "HEAD"], `resolve linked worktree head ${branch.branchName}`);
972
- plan.push({ branchName: branch.branchName, checkoutPath, seed: resolved.seed, action: currentHead === resolved.seed ? "keep" : "reset" });
973
+ const keep = currentHead === resolved.seed || !exactMirror && await tryGitAsync(checkoutPath, ["merge-base", "--is-ancestor", resolved.seed, currentHead]);
974
+ plan.push({ branchName: branch.branchName, checkoutPath, seed: resolved.seed, action: keep ? "keep" : "reset" });
973
975
  }
974
976
  const mutatedBranches = new Set(plan.filter(({ action }) => action !== "keep").map(({ branchName }) => branchName));
975
977
  if (mutatedBranches.size > 0) input.beforeDestructiveMutation(mutatedBranches);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/r5d-worker",
3
- "version": "0.0.104",
3
+ "version": "0.0.105",
4
4
  "type": "module",
5
5
  "main": "./dist/cjs/main.cjs",
6
6
  "module": "./dist/mjs/main.mjs",