@ricsam/r5d-worker 0.0.94 → 0.0.96
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 +145 -28
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/project-mirror-fetch-policy.cjs +41 -0
- package/dist/cjs/project-mirror-refs-token.cjs +51 -0
- package/dist/cjs/project-worktrees.cjs +40 -15
- package/dist/cjs/workspace-git-sync.cjs +146 -14
- package/dist/mjs/main.mjs +146 -28
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/project-mirror-fetch-policy.mjs +16 -0
- package/dist/mjs/project-mirror-refs-token.mjs +24 -0
- package/dist/mjs/project-worktrees.mjs +44 -15
- package/dist/mjs/workspace-git-sync.mjs +146 -14
- package/dist/types/main.d.ts +9 -0
- package/dist/types/project-mirror-fetch-policy.d.ts +29 -0
- package/dist/types/project-mirror-refs-token.d.ts +19 -0
- package/dist/types/project-worktrees.d.ts +21 -0
- package/dist/types/workspace-git-sync.d.ts +14 -1
- package/package.json +1 -1
package/dist/cjs/main.cjs
CHANGED
|
@@ -81,6 +81,7 @@ var import_repository_transition_policy = require("./repository-transition-polic
|
|
|
81
81
|
var import_supervisor = require("./supervisor.cjs");
|
|
82
82
|
var import_managed_paths = require("./managed-paths.cjs");
|
|
83
83
|
var import_project_worktrees = require("./project-worktrees.cjs");
|
|
84
|
+
var import_project_mirror_fetch_policy = require("./project-mirror-fetch-policy.cjs");
|
|
84
85
|
var import_project_snapshot_recovery_runner = require("./project-snapshot-recovery-runner.cjs");
|
|
85
86
|
var import_project_workspace_state = require("./project-workspace-state.cjs");
|
|
86
87
|
var import_workspace_git_sync = require("./workspace-git-sync.cjs");
|
|
@@ -113,6 +114,7 @@ const DEFAULT_READ_MAX_BYTES = 5e4;
|
|
|
113
114
|
const MAX_LINE_LENGTH = 2e3;
|
|
114
115
|
const WORKSPACE_GIT_QUIET_MS = 5e3;
|
|
115
116
|
const WORKSPACE_GIT_PERIODIC_MS = 6e4;
|
|
117
|
+
const PROJECT_MIRROR_OBSERVE_CONCURRENCY = 6;
|
|
116
118
|
const WORKSPACE_INCIDENT_CONFIG_REFRESH_TIMEOUT_MS = 6e4;
|
|
117
119
|
const PTY_INPUT_BUSY_GRACE_MS = 3e3;
|
|
118
120
|
const PTY_FOREGROUND_POLL_MS = 1e3;
|
|
@@ -1003,6 +1005,21 @@ function resolveWorkerFilePath(branchPath, inputPath, builtInPaths) {
|
|
|
1003
1005
|
function canonicalProjectRemoteUrl(baseUrl, projectId) {
|
|
1004
1006
|
return new URL(`/git/${projectId}.git`, baseUrl).toString();
|
|
1005
1007
|
}
|
|
1008
|
+
async function mapWithConcurrencyLimit(items, limit, task) {
|
|
1009
|
+
const results = new Array(items.length);
|
|
1010
|
+
let nextIndex = 0;
|
|
1011
|
+
await Promise.all(
|
|
1012
|
+
Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, async () => {
|
|
1013
|
+
while (true) {
|
|
1014
|
+
const index = nextIndex;
|
|
1015
|
+
nextIndex += 1;
|
|
1016
|
+
if (index >= items.length) return;
|
|
1017
|
+
results[index] = await task(items[index], index);
|
|
1018
|
+
}
|
|
1019
|
+
})
|
|
1020
|
+
);
|
|
1021
|
+
return results;
|
|
1022
|
+
}
|
|
1006
1023
|
function shellQuote(value) {
|
|
1007
1024
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
1008
1025
|
}
|
|
@@ -3462,6 +3479,10 @@ async function startWorker(options) {
|
|
|
3462
3479
|
const readyProjectIds = /* @__PURE__ */ new Set();
|
|
3463
3480
|
const reconciledProjectConfigFingerprints = /* @__PURE__ */ new Map();
|
|
3464
3481
|
const lastObservedProjectHeads = /* @__PURE__ */ new Map();
|
|
3482
|
+
const advertisedProjectMirrorRefsTokens = /* @__PURE__ */ new Map();
|
|
3483
|
+
const fetchedProjectMirrorRefsTokens = /* @__PURE__ */ new Map();
|
|
3484
|
+
const lastProjectMirrorFetchAtMs = /* @__PURE__ */ new Map();
|
|
3485
|
+
const projectMirrorFetchSkippingEnabled = process.env.R5D_PROJECT_MIRROR_FETCH_SKIP !== "0";
|
|
3465
3486
|
const pendingMirrorDeletes = /* @__PURE__ */ new Map();
|
|
3466
3487
|
let workspaceRemoteUrl = null;
|
|
3467
3488
|
let workspaceCredentialHelper = null;
|
|
@@ -3479,6 +3500,7 @@ async function startWorker(options) {
|
|
|
3479
3500
|
let automaticSyncInFlight = false;
|
|
3480
3501
|
let terminalReplayTimer;
|
|
3481
3502
|
let workspaceSyncRequestsInFlight = 0;
|
|
3503
|
+
let lastWorkspaceSyncMirrorObservationMs = 0;
|
|
3482
3504
|
let sessionArtifactSyncRequestsInFlight = 0;
|
|
3483
3505
|
let cliUpdateInProgress = false;
|
|
3484
3506
|
let reloadAfterClose = false;
|
|
@@ -3802,6 +3824,7 @@ async function startWorker(options) {
|
|
|
3802
3824
|
const branchKey = projectBranchKey(project.projectId, branch.branchName);
|
|
3803
3825
|
const creatorLocalIncarnation = creatorLocalIncarnations.get(branchKey) === branch.branchId;
|
|
3804
3826
|
const preservesCheckoutPathMove = checkoutPathMoveBranches.has(branchKey);
|
|
3827
|
+
const initialPublicationSourceBranch = creatorLocalIncarnation ? branch.sourceBranchName : null;
|
|
3805
3828
|
mounts.push({
|
|
3806
3829
|
id: projectMountId(project.projectId, branch.branchName),
|
|
3807
3830
|
hydrationIncarnationKey: branch.branchId,
|
|
@@ -3811,6 +3834,7 @@ async function startWorker(options) {
|
|
|
3811
3834
|
sourceMode: "git",
|
|
3812
3835
|
hydrateDeletionMode: "git",
|
|
3813
3836
|
preserveLocalOnInitialOuterAbsence: creatorLocalIncarnation,
|
|
3837
|
+
...initialPublicationSourceBranch ? { initialPublicationSourceRelativePath: workspaceProjectRelativePath(project.projectId, initialPublicationSourceBranch) } : {},
|
|
3814
3838
|
preserveLocalOnHydrationBasisChange: preservesCheckoutPathMove,
|
|
3815
3839
|
busy: () => projectBranchMountBusy(project.projectId, branch.branchName, branchPath),
|
|
3816
3840
|
mutationToken: () => projectWorkspaceMutationToken(project.projectId, branch.branchName),
|
|
@@ -3825,6 +3849,7 @@ async function startWorker(options) {
|
|
|
3825
3849
|
sourceMode: "all",
|
|
3826
3850
|
hydrateDeletionMode: "all",
|
|
3827
3851
|
preserveLocalOnInitialOuterAbsence: creatorLocalIncarnation,
|
|
3852
|
+
...initialPublicationSourceBranch ? { initialPublicationSourceRelativePath: workspacePlanRelativePath(project.projectId, initialPublicationSourceBranch) } : {},
|
|
3828
3853
|
preserveLocalOnHydrationBasisChange: preservesCheckoutPathMove,
|
|
3829
3854
|
busy: () => projectBranchMountBusy(project.projectId, branch.branchName, branchPath),
|
|
3830
3855
|
mutationToken: () => projectWorkspaceMutationToken(project.projectId, branch.branchName),
|
|
@@ -4104,6 +4129,17 @@ async function startWorker(options) {
|
|
|
4104
4129
|
for (const result of results) {
|
|
4105
4130
|
lastObservedProjectHeads.set(projectBranchKey(project.projectId, result.branchName), result.head);
|
|
4106
4131
|
}
|
|
4132
|
+
try {
|
|
4133
|
+
fetchedProjectMirrorRefsTokens.set(
|
|
4134
|
+
project.projectId,
|
|
4135
|
+
await (0, import_project_worktrees.computeLocalProjectMirrorRefsToken)({
|
|
4136
|
+
projectRoot: configuredProjectRoot(projectsRoot, project),
|
|
4137
|
+
primaryBranchName: primaryProjectBranch(project)
|
|
4138
|
+
})
|
|
4139
|
+
);
|
|
4140
|
+
} catch {
|
|
4141
|
+
fetchedProjectMirrorRefsTokens.delete(project.projectId);
|
|
4142
|
+
}
|
|
4107
4143
|
}
|
|
4108
4144
|
const publishedTombstoneIds = [
|
|
4109
4145
|
...new Set(
|
|
@@ -4129,6 +4165,7 @@ async function startWorker(options) {
|
|
|
4129
4165
|
credentialHelper: deletion.credentialHelper,
|
|
4130
4166
|
credentialUsername: deletion.credentialUsername
|
|
4131
4167
|
});
|
|
4168
|
+
fetchedProjectMirrorRefsTokens.delete(deletion.projectId);
|
|
4132
4169
|
}
|
|
4133
4170
|
if (deletion.tombstoneId && !deletion.projectDeleted) {
|
|
4134
4171
|
projectWorkspaceState = projectWorkspaceStateStore.recordMirrorRefDeletion({
|
|
@@ -4139,42 +4176,101 @@ async function startWorker(options) {
|
|
|
4139
4176
|
pendingMirrorDeletes.delete(key);
|
|
4140
4177
|
if (deletion.projectDeleted && !projectConfigById.has(deletion.projectId) && ![...pendingMirrorDeletes.values()].some((pending) => pending.projectId === deletion.projectId)) {
|
|
4141
4178
|
removeProjectCredentialStore(deletion.projectId);
|
|
4179
|
+
advertisedProjectMirrorRefsTokens.delete(deletion.projectId);
|
|
4180
|
+
fetchedProjectMirrorRefsTokens.delete(deletion.projectId);
|
|
4181
|
+
lastProjectMirrorFetchAtMs.delete(deletion.projectId);
|
|
4142
4182
|
}
|
|
4143
4183
|
lastObservedProjectHeads.delete(key);
|
|
4144
4184
|
}
|
|
4145
4185
|
};
|
|
4186
|
+
const observeSingleProjectMirrorBundle = async (project, options2) => {
|
|
4187
|
+
const connection = projectConnection(project);
|
|
4188
|
+
const projectRoot = configuredProjectRoot(projectsRoot, project);
|
|
4189
|
+
const primaryBranchName = primaryProjectBranch(project);
|
|
4190
|
+
if (options2.refreshRemote) {
|
|
4191
|
+
const advertisedBeforeFetch = advertisedProjectMirrorRefsTokens.get(project.projectId);
|
|
4192
|
+
const observations = await (0, import_project_worktrees.observeProjectMirrorHeads)({
|
|
4193
|
+
projectRoot,
|
|
4194
|
+
primaryBranchName,
|
|
4195
|
+
branchNames: project.branches.map(({ branchName }) => branchName),
|
|
4196
|
+
mirrorUrl: connection.mirrorUrl,
|
|
4197
|
+
credentialHelper: connection.credentialHelper,
|
|
4198
|
+
credentialUsername: connection.mirrorCredentialUsername,
|
|
4199
|
+
allowNonFastForward: options2.allowNonFastForward,
|
|
4200
|
+
branchIds: new Map(project.branches.map(({ branchId, branchName }) => [branchName, branchId]))
|
|
4201
|
+
});
|
|
4202
|
+
if (advertisedBeforeFetch === void 0) fetchedProjectMirrorRefsTokens.delete(project.projectId);
|
|
4203
|
+
else fetchedProjectMirrorRefsTokens.set(project.projectId, advertisedBeforeFetch);
|
|
4204
|
+
lastProjectMirrorFetchAtMs.set(project.projectId, Date.now());
|
|
4205
|
+
return { projectId: project.projectId, projectRoot, primaryBranchName, observations };
|
|
4206
|
+
}
|
|
4207
|
+
return {
|
|
4208
|
+
projectId: project.projectId,
|
|
4209
|
+
projectRoot,
|
|
4210
|
+
primaryBranchName,
|
|
4211
|
+
observations: await (0, import_project_worktrees.observeProjectMirrorHeads)({
|
|
4212
|
+
projectRoot,
|
|
4213
|
+
primaryBranchName,
|
|
4214
|
+
branchNames: project.branches.map(({ branchName }) => branchName),
|
|
4215
|
+
mirrorUrl: connection.mirrorUrl,
|
|
4216
|
+
credentialHelper: connection.credentialHelper,
|
|
4217
|
+
credentialUsername: connection.mirrorCredentialUsername,
|
|
4218
|
+
allowNonFastForward: options2.allowNonFastForward,
|
|
4219
|
+
branchIds: new Map(project.branches.map(({ branchId, branchName }) => [branchName, branchId])),
|
|
4220
|
+
refreshRemote: false
|
|
4221
|
+
})
|
|
4222
|
+
};
|
|
4223
|
+
};
|
|
4146
4224
|
const observeProjectHeadsBeforeOuterWorkspace = async (input) => {
|
|
4147
|
-
const
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
const
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4225
|
+
const observationStartedAt = Date.now();
|
|
4226
|
+
const eligibleProjects = [...projectConfigById.values()].filter(
|
|
4227
|
+
(project) => !project.executionDisabled && readyProjectIds.has(project.projectId) && project.branches.length > 0
|
|
4228
|
+
);
|
|
4229
|
+
try {
|
|
4230
|
+
if (input.failClosed) {
|
|
4231
|
+
const bundles2 = [];
|
|
4232
|
+
for (const project of eligibleProjects) {
|
|
4233
|
+
bundles2.push(await observeSingleProjectMirrorBundle(project, { allowNonFastForward: input.allowNonFastForward, refreshRemote: true }));
|
|
4234
|
+
}
|
|
4235
|
+
return bundles2;
|
|
4236
|
+
}
|
|
4237
|
+
let fetchedCount = 0;
|
|
4238
|
+
const bundles = await mapWithConcurrencyLimit(
|
|
4239
|
+
eligibleProjects,
|
|
4240
|
+
PROJECT_MIRROR_OBSERVE_CONCURRENCY,
|
|
4241
|
+
async (project) => {
|
|
4242
|
+
try {
|
|
4243
|
+
const decision = (0, import_project_mirror_fetch_policy.projectMirrorFetchDecision)({
|
|
4244
|
+
advertisedToken: advertisedProjectMirrorRefsTokens.get(project.projectId),
|
|
4245
|
+
fetchedToken: fetchedProjectMirrorRefsTokens.get(project.projectId),
|
|
4246
|
+
lastFetchAtMs: lastProjectMirrorFetchAtMs.get(project.projectId),
|
|
4247
|
+
nowMs: Date.now(),
|
|
4248
|
+
skippingEnabled: projectMirrorFetchSkippingEnabled
|
|
4249
|
+
});
|
|
4250
|
+
if (decision.fetch) fetchedCount += 1;
|
|
4251
|
+
return await observeSingleProjectMirrorBundle(project, {
|
|
4252
|
+
allowNonFastForward: input.allowNonFastForward,
|
|
4253
|
+
refreshRemote: decision.fetch
|
|
4254
|
+
});
|
|
4255
|
+
} catch (error) {
|
|
4256
|
+
process.stderr.write(
|
|
4257
|
+
`[r5d-worker] failed to observe project mirror heads before workspace update: ${error instanceof Error ? error.message : String(error)}
|
|
4258
|
+
`
|
|
4259
|
+
);
|
|
4260
|
+
return null;
|
|
4261
|
+
}
|
|
4262
|
+
}
|
|
4263
|
+
);
|
|
4264
|
+
if (fetchedCount > 0) {
|
|
4171
4265
|
process.stderr.write(
|
|
4172
|
-
`[r5d-worker]
|
|
4266
|
+
`[r5d-worker] project mirror observation fetched ${fetchedCount} of ${eligibleProjects.length} mirror(s)
|
|
4173
4267
|
`
|
|
4174
4268
|
);
|
|
4175
4269
|
}
|
|
4270
|
+
return bundles.filter((bundle) => bundle !== null);
|
|
4271
|
+
} finally {
|
|
4272
|
+
lastWorkspaceSyncMirrorObservationMs = Date.now() - observationStartedAt;
|
|
4176
4273
|
}
|
|
4177
|
-
return bundles;
|
|
4178
4274
|
};
|
|
4179
4275
|
const applyObservedProjectHeadsAfterInboundWorkspace = async (bundles, activeMountIds, requireObservedHeads, integratedWorkspaceHead) => {
|
|
4180
4276
|
const active = new Set(activeMountIds);
|
|
@@ -4353,6 +4449,12 @@ async function startWorker(options) {
|
|
|
4353
4449
|
}
|
|
4354
4450
|
});
|
|
4355
4451
|
input.assertStillAdmitted?.();
|
|
4452
|
+
if (result.initialPublicationMountIds && result.initialPublicationMountIds.length > 0) {
|
|
4453
|
+
process.stderr.write(
|
|
4454
|
+
`[r5d-worker] published first checkout copies above the automatic diff-size limit, measured against their source subtrees at ${result.diffSizeBytes} bytes: ${result.initialPublicationMountIds.join(", ")}
|
|
4455
|
+
`
|
|
4456
|
+
);
|
|
4457
|
+
}
|
|
4356
4458
|
if (["no_change", "updated", "pushed"].includes(result.outcome) && !outerRemediation) {
|
|
4357
4459
|
await applyObservedProjectHeadsAfterInboundWorkspace(
|
|
4358
4460
|
observedProjectHeads,
|
|
@@ -4443,6 +4545,7 @@ async function startWorker(options) {
|
|
|
4443
4545
|
result = await workspaceSyncSingleFlight.runExclusive(async () => {
|
|
4444
4546
|
queueEnteredAt = Date.now();
|
|
4445
4547
|
syncStartedAt = Date.now();
|
|
4548
|
+
lastWorkspaceSyncMirrorObservationMs = 0;
|
|
4446
4549
|
if (!deferredWorkspaceSyncTriggerIsAllowed(deferredWorkspaceConfiguration, activeWorkspaceIncidentId, input.trigger)) {
|
|
4447
4550
|
return await failedWorkspaceSyncResult(
|
|
4448
4551
|
attemptId,
|
|
@@ -4527,7 +4630,9 @@ async function startWorker(options) {
|
|
|
4527
4630
|
telemetry: {
|
|
4528
4631
|
totalMs: finishedAt - requestedAt,
|
|
4529
4632
|
queueMs: queueEnteredAt - requestedAt,
|
|
4530
|
-
|
|
4633
|
+
// Duration of the pre-outer mirror-head observation phase; near zero
|
|
4634
|
+
// on a cycle whose token-gated observation skipped every fetch.
|
|
4635
|
+
prepareMs: lastWorkspaceSyncMirrorObservationMs,
|
|
4531
4636
|
synchronizeMs: finishedAt - syncStartedAt
|
|
4532
4637
|
}
|
|
4533
4638
|
};
|
|
@@ -5245,7 +5350,8 @@ async function startWorker(options) {
|
|
|
5245
5350
|
workspaceIncidentConfigDeferralV1: true,
|
|
5246
5351
|
workspaceConfigResetToCanonicalV1: true,
|
|
5247
5352
|
projectBranchDeletionFastAckV1: true,
|
|
5248
|
-
projectMirrorLeaseV1: true
|
|
5353
|
+
projectMirrorLeaseV1: true,
|
|
5354
|
+
projectMirrorRefsTokensV1: true
|
|
5249
5355
|
},
|
|
5250
5356
|
projectRoot: projectsRoot,
|
|
5251
5357
|
artifactRoot,
|
|
@@ -5283,6 +5389,17 @@ async function startWorker(options) {
|
|
|
5283
5389
|
if (message.type === "connected") {
|
|
5284
5390
|
return;
|
|
5285
5391
|
}
|
|
5392
|
+
if (message.type === "project_mirror_refs_tokens") {
|
|
5393
|
+
advertisedProjectMirrorRefsTokens.clear();
|
|
5394
|
+
if (message.tokens && typeof message.tokens === "object") {
|
|
5395
|
+
for (const [projectId, token2] of Object.entries(message.tokens)) {
|
|
5396
|
+
if (typeof token2 === "string" && /^[0-9a-f]{64}$/.test(token2)) {
|
|
5397
|
+
advertisedProjectMirrorRefsTokens.set(projectId, token2);
|
|
5398
|
+
}
|
|
5399
|
+
}
|
|
5400
|
+
}
|
|
5401
|
+
return;
|
|
5402
|
+
}
|
|
5286
5403
|
if (message.type === "workspace_config") {
|
|
5287
5404
|
const receiptGeneration = ++workspaceConfigurationReceiptGeneration;
|
|
5288
5405
|
const refreshesDeferredConfiguration = deferredWorkspaceConfiguration !== null && activeWorkspaceIncidentId === null && message.deferWorkspaceSyncForIncidentId === void 0;
|
package/dist/cjs/package.json
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var project_mirror_fetch_policy_exports = {};
|
|
20
|
+
__export(project_mirror_fetch_policy_exports, {
|
|
21
|
+
PROJECT_MIRROR_FETCH_BACKSTOP_MS: () => PROJECT_MIRROR_FETCH_BACKSTOP_MS,
|
|
22
|
+
projectMirrorFetchDecision: () => projectMirrorFetchDecision
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(project_mirror_fetch_policy_exports);
|
|
25
|
+
const PROJECT_MIRROR_FETCH_BACKSTOP_MS = 10 * 6e4;
|
|
26
|
+
function projectMirrorFetchDecision(input) {
|
|
27
|
+
if (!input.skippingEnabled) return { fetch: true, reason: "skipping_disabled" };
|
|
28
|
+
if (input.advertisedToken === void 0) return { fetch: true, reason: "no_advertised_token" };
|
|
29
|
+
if (input.fetchedToken === void 0) return { fetch: true, reason: "never_fetched" };
|
|
30
|
+
if (input.advertisedToken !== input.fetchedToken) return { fetch: true, reason: "token_changed" };
|
|
31
|
+
const backstopMs = input.backstopMs ?? PROJECT_MIRROR_FETCH_BACKSTOP_MS;
|
|
32
|
+
if (input.lastFetchAtMs === void 0 || input.nowMs - input.lastFetchAtMs >= backstopMs) {
|
|
33
|
+
return { fetch: true, reason: "backstop_elapsed" };
|
|
34
|
+
}
|
|
35
|
+
return { fetch: false, reason: "token_match" };
|
|
36
|
+
}
|
|
37
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
38
|
+
0 && (module.exports = {
|
|
39
|
+
PROJECT_MIRROR_FETCH_BACKSTOP_MS,
|
|
40
|
+
projectMirrorFetchDecision
|
|
41
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var project_mirror_refs_token_exports = {};
|
|
20
|
+
__export(project_mirror_refs_token_exports, {
|
|
21
|
+
PROJECT_MIRROR_REF_PREFIX: () => PROJECT_MIRROR_REF_PREFIX,
|
|
22
|
+
PROJECT_SERVER_SYNCED_REF_PREFIX: () => PROJECT_SERVER_SYNCED_REF_PREFIX,
|
|
23
|
+
canonicalizeLocalProjectMirrorRefs: () => canonicalizeLocalProjectMirrorRefs,
|
|
24
|
+
hashProjectMirrorRefs: () => hashProjectMirrorRefs
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(project_mirror_refs_token_exports);
|
|
27
|
+
var import_node_crypto = require("node:crypto");
|
|
28
|
+
const PROJECT_MIRROR_REF_PREFIX = "refs/r5d/mirror/";
|
|
29
|
+
const PROJECT_SERVER_SYNCED_REF_PREFIX = "refs/r5d/server-synced/";
|
|
30
|
+
function hashProjectMirrorRefs(refs) {
|
|
31
|
+
const lines = refs.map(({ objectName, refname }) => `${objectName} ${refname}`).sort((left, right) => left < right ? -1 : left > right ? 1 : 0);
|
|
32
|
+
return (0, import_node_crypto.createHash)("sha256").update(lines.join("\n")).digest("hex");
|
|
33
|
+
}
|
|
34
|
+
function canonicalizeLocalProjectMirrorRefs(refs) {
|
|
35
|
+
const canonical = [];
|
|
36
|
+
for (const { refname, objectName } of refs) {
|
|
37
|
+
if (refname.startsWith(PROJECT_MIRROR_REF_PREFIX)) {
|
|
38
|
+
canonical.push({ refname: `refs/heads/${refname.slice(PROJECT_MIRROR_REF_PREFIX.length)}`, objectName });
|
|
39
|
+
} else if (refname.startsWith(PROJECT_SERVER_SYNCED_REF_PREFIX)) {
|
|
40
|
+
canonical.push({ refname, objectName });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return canonical;
|
|
44
|
+
}
|
|
45
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
46
|
+
0 && (module.exports = {
|
|
47
|
+
PROJECT_MIRROR_REF_PREFIX,
|
|
48
|
+
PROJECT_SERVER_SYNCED_REF_PREFIX,
|
|
49
|
+
canonicalizeLocalProjectMirrorRefs,
|
|
50
|
+
hashProjectMirrorRefs
|
|
51
|
+
});
|
|
@@ -32,6 +32,7 @@ __export(project_worktrees_exports, {
|
|
|
32
32
|
ProjectBranchCreationRollbackIncompleteError: () => ProjectBranchCreationRollbackIncompleteError,
|
|
33
33
|
applyObservedProjectMirrorHeads: () => applyObservedProjectMirrorHeads,
|
|
34
34
|
assertProjectMirrorHeadsPushed: () => assertProjectMirrorHeadsPushed,
|
|
35
|
+
computeLocalProjectMirrorRefsToken: () => computeLocalProjectMirrorRefsToken,
|
|
35
36
|
createLinkedProjectBranch: () => createLinkedProjectBranch,
|
|
36
37
|
createOrRetryLinkedProjectBranch: () => createOrRetryLinkedProjectBranch,
|
|
37
38
|
deleteLinkedProjectBranch: () => deleteLinkedProjectBranch,
|
|
@@ -57,6 +58,7 @@ var import_node_os = __toESM(require("node:os"), 1);
|
|
|
57
58
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
58
59
|
var import_git_process_environment = require("./git-process-environment.cjs");
|
|
59
60
|
var import_managed_paths = require("./managed-paths.cjs");
|
|
61
|
+
var import_project_mirror_refs_token = require("./project-mirror-refs-token.cjs");
|
|
60
62
|
var import_working_tree_mirror = require("./working-tree-mirror.cjs");
|
|
61
63
|
const PROJECT_WORKTREE_SNAPSHOT_PREFIX = "r5d-project-worktrees-";
|
|
62
64
|
const PROJECT_WORKTREE_SNAPSHOT_MANIFEST = "transaction.json";
|
|
@@ -1294,6 +1296,7 @@ ${deleted.stdout}`)) {
|
|
|
1294
1296
|
`Delete hidden project mirror for ${input.branchName}: ${deleted.stderr || deleted.stdout || `git exited ${deleted.exitCode}`}`
|
|
1295
1297
|
);
|
|
1296
1298
|
}
|
|
1299
|
+
await gitResultAsync(input.gitDirectory, ["update-ref", "-d", `refs/r5d/mirror/${input.branchName}`]);
|
|
1297
1300
|
}
|
|
1298
1301
|
async function pushProjectMirrorHeads(input) {
|
|
1299
1302
|
const results = [];
|
|
@@ -1351,6 +1354,7 @@ async function pushProjectMirrorHeads(input) {
|
|
|
1351
1354
|
if (pushed.exitCode !== 0) {
|
|
1352
1355
|
throw new Error(`Push hidden project mirror for ${branchName}: ${pushed.stderr || pushed.stdout || `git exited ${pushed.exitCode}`}`);
|
|
1353
1356
|
}
|
|
1357
|
+
await gitAsync(checkoutPath, ["update-ref", `refs/r5d/mirror/${branchName}`, head], `record pushed mirror tip ${branchName}`);
|
|
1354
1358
|
results.push({ branchName, head, pushed: true });
|
|
1355
1359
|
}
|
|
1356
1360
|
return results;
|
|
@@ -1363,21 +1367,23 @@ function assertProjectMirrorHeadsPushed(results) {
|
|
|
1363
1367
|
}
|
|
1364
1368
|
async function observeProjectMirrorHeads(input) {
|
|
1365
1369
|
const primaryPath = branchPath(input.projectRoot, input.primaryBranchName);
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1370
|
+
if (input.refreshRemote !== false) {
|
|
1371
|
+
const fetch = await gitResultAsync(
|
|
1372
|
+
primaryPath,
|
|
1373
|
+
[
|
|
1374
|
+
...(0, import_git_process_environment.gitTransportSecurityArgs)(input.mirrorUrl, input.credentialHelper, input.credentialUsername),
|
|
1375
|
+
"fetch",
|
|
1376
|
+
"--no-recurse-submodules",
|
|
1377
|
+
"--prune",
|
|
1378
|
+
input.mirrorUrl,
|
|
1379
|
+
"+refs/heads/*:refs/r5d/mirror/*",
|
|
1380
|
+
"+refs/r5d/server-synced/*:refs/r5d/server-synced/*"
|
|
1381
|
+
],
|
|
1382
|
+
PROJECT_GIT_TRANSPORT_TIMEOUT_MS
|
|
1383
|
+
);
|
|
1384
|
+
if (fetch.exitCode !== 0)
|
|
1385
|
+
throw new Error(`Refresh project head mirror: ${fetch.stderr || fetch.stdout || `git exited ${fetch.exitCode}`}`);
|
|
1386
|
+
}
|
|
1381
1387
|
const observations = [];
|
|
1382
1388
|
for (const branchName of [...input.branchNames].sort()) {
|
|
1383
1389
|
const checkoutPath = branchPath(input.projectRoot, branchName);
|
|
@@ -1423,6 +1429,24 @@ async function observeProjectMirrorHeads(input) {
|
|
|
1423
1429
|
}
|
|
1424
1430
|
return observations;
|
|
1425
1431
|
}
|
|
1432
|
+
async function computeLocalProjectMirrorRefsToken(input) {
|
|
1433
|
+
const primaryPath = branchPath(input.projectRoot, input.primaryBranchName);
|
|
1434
|
+
const rows = await gitAsync(
|
|
1435
|
+
primaryPath,
|
|
1436
|
+
["for-each-ref", "--format=%(objectname) %(refname)", import_project_mirror_refs_token.PROJECT_MIRROR_REF_PREFIX, import_project_mirror_refs_token.PROJECT_SERVER_SYNCED_REF_PREFIX],
|
|
1437
|
+
"list cached project mirror refs"
|
|
1438
|
+
);
|
|
1439
|
+
const refs = rows.split(/\r?\n/).filter(Boolean).map((row) => {
|
|
1440
|
+
const separator = row.indexOf(" ");
|
|
1441
|
+
const objectName = separator < 0 ? "" : row.slice(0, separator);
|
|
1442
|
+
const refname = separator < 0 ? "" : row.slice(separator + 1);
|
|
1443
|
+
if (!/^[0-9a-f]{40,64}$/.test(objectName) || refname.length === 0) {
|
|
1444
|
+
throw new Error(`Invalid cached mirror ref listing row: ${row}`);
|
|
1445
|
+
}
|
|
1446
|
+
return { refname, objectName };
|
|
1447
|
+
});
|
|
1448
|
+
return (0, import_project_mirror_refs_token.hashProjectMirrorRefs)((0, import_project_mirror_refs_token.canonicalizeLocalProjectMirrorRefs)(refs));
|
|
1449
|
+
}
|
|
1426
1450
|
async function applyObservedProjectMirrorHeads(input) {
|
|
1427
1451
|
const results = [];
|
|
1428
1452
|
for (const observation of [...input.observations].sort((left, right) => left.branchName.localeCompare(right.branchName))) {
|
|
@@ -1505,6 +1529,7 @@ const projectWorktreesTestHarness = {
|
|
|
1505
1529
|
ProjectBranchCreationRollbackIncompleteError,
|
|
1506
1530
|
applyObservedProjectMirrorHeads,
|
|
1507
1531
|
assertProjectMirrorHeadsPushed,
|
|
1532
|
+
computeLocalProjectMirrorRefsToken,
|
|
1508
1533
|
createLinkedProjectBranch,
|
|
1509
1534
|
createOrRetryLinkedProjectBranch,
|
|
1510
1535
|
deleteLinkedProjectBranch,
|