@ricsam/r5d-worker 0.0.82 → 0.0.86
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 +470 -38
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/workspace-automatic-sync-policy.cjs +12 -2
- package/dist/cjs/workspace-command-sync-policy.cjs +21 -0
- package/dist/cjs/workspace-git-sync.cjs +79 -3
- package/dist/mjs/main.mjs +478 -40
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/workspace-automatic-sync-policy.mjs +9 -1
- package/dist/mjs/workspace-command-sync-policy.mjs +20 -0
- package/dist/mjs/workspace-git-sync.mjs +76 -3
- package/dist/types/main.d.ts +349 -0
- package/dist/types/workspace-automatic-sync-policy.d.ts +17 -0
- package/dist/types/workspace-command-sync-policy.d.ts +7 -0
- package/dist/types/workspace-git-sync.d.ts +36 -0
- package/package.json +1 -1
package/dist/mjs/package.json
CHANGED
|
@@ -15,6 +15,12 @@ function projectBranchHasActiveWorkspaceTarget(projectId, branchName, activeTarg
|
|
|
15
15
|
}
|
|
16
16
|
return false;
|
|
17
17
|
}
|
|
18
|
+
function projectBranchMountBusyDuringExclusiveSync(input) {
|
|
19
|
+
return input.executionDisabled || input.worktreeOperationInProgress || input.retainedCanonicalProcessGroup || projectBranchHasActiveWorkspaceTarget(input.projectId, input.branchName, input.activeTargets);
|
|
20
|
+
}
|
|
21
|
+
function workspacePlansMountBusyDuringExclusiveSync(activeTargets, retainedCanonicalProcessGroup = false) {
|
|
22
|
+
return retainedCanonicalProcessGroup || hasActiveVisibleProjectsWorkspaceTarget(activeTargets);
|
|
23
|
+
}
|
|
18
24
|
function shouldDeferAutomaticWorkspaceSyncForPendingBranch(pendingCreatedBranches, activeTargets) {
|
|
19
25
|
if (pendingCreatedBranches.length === 0) return false;
|
|
20
26
|
const targets = [...activeTargets];
|
|
@@ -36,5 +42,7 @@ export {
|
|
|
36
42
|
pendingCreatedBranchAutomaticSyncDeferral,
|
|
37
43
|
pendingCreatedBranchKey,
|
|
38
44
|
projectBranchHasActiveWorkspaceTarget,
|
|
39
|
-
|
|
45
|
+
projectBranchMountBusyDuringExclusiveSync,
|
|
46
|
+
shouldDeferAutomaticWorkspaceSyncForPendingBranch,
|
|
47
|
+
workspacePlansMountBusyDuringExclusiveSync
|
|
40
48
|
};
|
|
@@ -20,12 +20,32 @@ function shouldSerializeWorkspaceCommand(target) {
|
|
|
20
20
|
function runWorkspaceCommand(target, coordinator, operation) {
|
|
21
21
|
return shouldSerializeWorkspaceCommand(target) ? coordinator.runMutation(operation) : Promise.resolve().then(operation);
|
|
22
22
|
}
|
|
23
|
+
async function runReservedWorkspaceCommand(target, coordinator, operation, releaseReservation) {
|
|
24
|
+
let released = false;
|
|
25
|
+
const releaseOnce = () => {
|
|
26
|
+
if (released) return;
|
|
27
|
+
released = true;
|
|
28
|
+
releaseReservation();
|
|
29
|
+
};
|
|
30
|
+
try {
|
|
31
|
+
return await runWorkspaceCommand(target, coordinator, async () => {
|
|
32
|
+
try {
|
|
33
|
+
return await operation();
|
|
34
|
+
} finally {
|
|
35
|
+
releaseOnce();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
} finally {
|
|
39
|
+
releaseOnce();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
23
42
|
function acquireWorkspaceCommandMutation(target, coordinator) {
|
|
24
43
|
return shouldSerializeWorkspaceCommand(target) ? coordinator.acquireMutation() : Promise.resolve(void 0);
|
|
25
44
|
}
|
|
26
45
|
export {
|
|
27
46
|
acquireWorkspaceCommandMutation,
|
|
28
47
|
reserveWorkspaceCommandAfterCurrentSync,
|
|
48
|
+
runReservedWorkspaceCommand,
|
|
29
49
|
runWorkspaceCommand,
|
|
30
50
|
shouldSerializeWorkspaceCommand
|
|
31
51
|
};
|
|
@@ -15,6 +15,15 @@ const WORKSPACE_GIT_INTEGRATED_REF = "refs/r5d/workspace-local/integrated";
|
|
|
15
15
|
const WORKSPACE_GIT_HYDRATED_RECEIPT = "r5d/workspace-hydrated-head";
|
|
16
16
|
const WORKSPACE_GIT_HYDRATION_TRANSACTION = "r5d/workspace-hydration-transaction";
|
|
17
17
|
const WORKSPACE_GIT_CHECKOUT_DURABILITY = "r5d/workspace-checkout-durability";
|
|
18
|
+
function workspaceGitMountsForRemediation(mounts) {
|
|
19
|
+
return mounts.map((mount) => ({ ...mount, busy: mount.busyForRecovery ?? mount.busy }));
|
|
20
|
+
}
|
|
21
|
+
class WorkspaceRemediationAncestryError extends Error {
|
|
22
|
+
constructor(message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "WorkspaceRemediationAncestryError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
18
27
|
const NON_RECURSIVE_GIT_CONFIG = [
|
|
19
28
|
"-c",
|
|
20
29
|
"submodule.recurse=false",
|
|
@@ -54,6 +63,29 @@ function revParse(workspacePath, revision) {
|
|
|
54
63
|
const result = gitResult(workspacePath, ["rev-parse", "--verify", revision]);
|
|
55
64
|
return result.exitCode === 0 ? result.stdout : null;
|
|
56
65
|
}
|
|
66
|
+
function requiredWorkspaceAncestorHeads(value) {
|
|
67
|
+
if (value === void 0) return [];
|
|
68
|
+
if (!Array.isArray(value) || value.length === 0 || value.some((head) => typeof head !== "string" || !/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(head)) || new Set(value).size !== value.length) {
|
|
69
|
+
throw new WorkspaceRemediationAncestryError("Workspace remediation ancestor requirements are invalid");
|
|
70
|
+
}
|
|
71
|
+
return [...value];
|
|
72
|
+
}
|
|
73
|
+
function assertWorkspaceRemediationAncestry(input) {
|
|
74
|
+
if (input.requiredAncestorHeads.length === 0) return;
|
|
75
|
+
if (!input.currentHead) throw new WorkspaceRemediationAncestryError("Workspace remediation has no resolved HEAD to verify");
|
|
76
|
+
for (const requiredHead of input.requiredAncestorHeads) {
|
|
77
|
+
if (!tryGit(input.workspacePath, ["cat-file", "-e", `${requiredHead}^{commit}`]) || !tryGit(input.workspacePath, ["merge-base", "--is-ancestor", requiredHead, input.currentHead])) {
|
|
78
|
+
throw new WorkspaceRemediationAncestryError(
|
|
79
|
+
`Workspace remediation HEAD does not descend from required conflict commit ${requiredHead}`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (!input.remoteHead || !tryGit(input.workspacePath, ["cat-file", "-e", `${input.remoteHead}^{commit}`]) || !tryGit(input.workspacePath, ["merge-base", "--is-ancestor", input.remoteHead, input.currentHead])) {
|
|
84
|
+
throw new WorkspaceRemediationAncestryError(
|
|
85
|
+
"Fetched workspace head is not an ancestor of the resolved remediation HEAD; merge it explicitly before synchronizing"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
57
89
|
function updateIntegratedWorkspaceHead(workspacePath, head) {
|
|
58
90
|
git(workspacePath, ["update-ref", WORKSPACE_GIT_INTEGRATED_REF, head], "record integrated workspace head");
|
|
59
91
|
}
|
|
@@ -923,6 +955,15 @@ function configureWorkspaceRepository(input) {
|
|
|
923
955
|
);
|
|
924
956
|
git(input.workspacePath, ["config", "--local", "core.fsyncMethod", "fsync"], "configure workspace fsync method");
|
|
925
957
|
}
|
|
958
|
+
function configureExistingWorkspaceGitForRemediation(input) {
|
|
959
|
+
const workspacePath = path.resolve(input.workspacePath);
|
|
960
|
+
const workspaceStatus = lstatIfExists(workspacePath);
|
|
961
|
+
const gitStatus = lstatIfExists(path.join(workspacePath, ".git"));
|
|
962
|
+
if (!workspaceStatus?.isDirectory() || workspaceStatus.isSymbolicLink() || !gitStatus?.isDirectory() || gitStatus.isSymbolicLink()) {
|
|
963
|
+
throw new Error("Active workspace remediation requires a regular existing canonical synchronization checkout");
|
|
964
|
+
}
|
|
965
|
+
configureWorkspaceRepository({ ...input, workspacePath });
|
|
966
|
+
}
|
|
926
967
|
function fetchWorkspaceHead(workspacePath, remoteUrl, credentialHelper, credentialUsername) {
|
|
927
968
|
const result = gitResult(workspacePath, [
|
|
928
969
|
...gitTransportSecurityArgs(remoteUrl, credentialHelper, credentialUsername),
|
|
@@ -1261,6 +1302,9 @@ function resetWorkspaceGit(input) {
|
|
|
1261
1302
|
const outerPath = path.join(workspacePath, ...mount.workspaceRelativePath.replace(/\\/g, "/").split("/"));
|
|
1262
1303
|
return fs.existsSync(outerPath);
|
|
1263
1304
|
});
|
|
1305
|
+
const bootstrapMountIds = new Set(bootstrapMounts.map(({ id }) => id));
|
|
1306
|
+
const durablyAbsentMounts = selected.skipped.filter((mount) => !bootstrapMountIds.has(mount.id) && mount.sourceMode === "all");
|
|
1307
|
+
const uncoveredSkippedMounts = selected.skipped.filter((mount) => !bootstrapMountIds.has(mount.id) && mount.sourceMode !== "all");
|
|
1264
1308
|
const hydrationMounts = [...selected.active, ...bootstrapMounts];
|
|
1265
1309
|
const requiredLiveMounts = [
|
|
1266
1310
|
...new Map([...requiredLiveMountsBeforeHydration, ...bootstrapMounts].map((mount) => [mount.id, mount])).values()
|
|
@@ -1268,7 +1312,7 @@ function resetWorkspaceGit(input) {
|
|
|
1268
1312
|
const hydration = hydrateWorkspaceGitMountsTransactionally({
|
|
1269
1313
|
workspacePath,
|
|
1270
1314
|
mounts: hydrationMounts,
|
|
1271
|
-
durabilityMounts: [...requiredLiveMounts, ...selected.tombstones],
|
|
1315
|
+
durabilityMounts: [...requiredLiveMounts, ...selected.tombstones, ...durablyAbsentMounts],
|
|
1272
1316
|
receiptMounts: input.mounts,
|
|
1273
1317
|
requiredMounts: requiredLiveMounts,
|
|
1274
1318
|
recordCurrentHead: true
|
|
@@ -1284,7 +1328,7 @@ function resetWorkspaceGit(input) {
|
|
|
1284
1328
|
remoteHead,
|
|
1285
1329
|
discardedPaths,
|
|
1286
1330
|
activeMountIds: hydration.hydratedMountIds,
|
|
1287
|
-
skippedMountIds: [.../* @__PURE__ */ new Set([...
|
|
1331
|
+
skippedMountIds: [.../* @__PURE__ */ new Set([...uncoveredSkippedMounts.map(({ id }) => id), ...hydration.skippedMountIds])].sort()
|
|
1288
1332
|
};
|
|
1289
1333
|
}
|
|
1290
1334
|
function stagedPaths(workspacePath) {
|
|
@@ -1424,8 +1468,16 @@ async function synchronizeWorkspaceGit(input) {
|
|
|
1424
1468
|
const maxDiffBytes = input.maxDiffBytes ?? MAX_WORKSPACE_GIT_DIFF_BYTES;
|
|
1425
1469
|
const maxPushAttempts = Math.max(1, input.maxPushAttempts ?? 4);
|
|
1426
1470
|
validateMounts(workspacePath, input.mounts);
|
|
1471
|
+
const requiredAncestorHeads = requiredWorkspaceAncestorHeads(input.requiredAncestorHeads);
|
|
1427
1472
|
const preserveResolutionInProgress = input.skipMountMirror === true;
|
|
1428
1473
|
const initial = ensureWorkspaceGitClone({ ...input, workspacePath, preserveResolutionInProgress });
|
|
1474
|
+
assertWorkspaceRemediationAncestry({
|
|
1475
|
+
workspacePath,
|
|
1476
|
+
currentHead: initial.localHead,
|
|
1477
|
+
remoteHead: initial.remoteHead,
|
|
1478
|
+
requiredAncestorHeads
|
|
1479
|
+
});
|
|
1480
|
+
const verifiedAncestorHeads = requiredAncestorHeads.length > 0 ? requiredAncestorHeads : void 0;
|
|
1429
1481
|
const startingHead = initial.localHead;
|
|
1430
1482
|
const receiptBeforeInitialHydration = readHydratedWorkspaceReceipt(workspacePath);
|
|
1431
1483
|
const deferredMountIds = /* @__PURE__ */ new Set();
|
|
@@ -1517,6 +1569,7 @@ async function synchronizeWorkspaceGit(input) {
|
|
|
1517
1569
|
conflictPaths: merged.conflictPaths,
|
|
1518
1570
|
conflictSnapshotRefs: refs,
|
|
1519
1571
|
conflictKind: "projection_merge",
|
|
1572
|
+
...verifiedAncestorHeads ? { verifiedAncestorHeads } : {},
|
|
1520
1573
|
error: merged.error
|
|
1521
1574
|
};
|
|
1522
1575
|
}
|
|
@@ -1640,6 +1693,12 @@ async function synchronizeWorkspaceGit(input) {
|
|
|
1640
1693
|
let rebaseCount = 0;
|
|
1641
1694
|
let updated = false;
|
|
1642
1695
|
for (let pushAttempt = 0; pushAttempt < maxPushAttempts; pushAttempt += 1) {
|
|
1696
|
+
assertWorkspaceRemediationAncestry({
|
|
1697
|
+
workspacePath,
|
|
1698
|
+
currentHead: revParse(workspacePath, "HEAD"),
|
|
1699
|
+
remoteHead,
|
|
1700
|
+
requiredAncestorHeads
|
|
1701
|
+
});
|
|
1643
1702
|
const reconciled = synchronizeWithFetchedHead({ workspacePath, remoteHead, attemptId });
|
|
1644
1703
|
if (reconciled.kind === "conflict") {
|
|
1645
1704
|
const localHead2 = revParse(workspacePath, "HEAD");
|
|
@@ -1657,6 +1716,7 @@ async function synchronizeWorkspaceGit(input) {
|
|
|
1657
1716
|
conflictPaths: reconciled.conflictPaths,
|
|
1658
1717
|
conflictSnapshotRefs: reconciled.refs,
|
|
1659
1718
|
conflictKind: "integration_rebase",
|
|
1719
|
+
...verifiedAncestorHeads ? { verifiedAncestorHeads } : {},
|
|
1660
1720
|
error: reconciled.error
|
|
1661
1721
|
};
|
|
1662
1722
|
}
|
|
@@ -1676,11 +1736,13 @@ async function synchronizeWorkspaceGit(input) {
|
|
|
1676
1736
|
diffSizeBytes: 0,
|
|
1677
1737
|
affectedPaths: [],
|
|
1678
1738
|
...classifiedMounts,
|
|
1739
|
+
...verifiedAncestorHeads ? { verifiedAncestorHeads } : {},
|
|
1679
1740
|
...projectionWarning ? { error: projectionWarning } : {}
|
|
1680
1741
|
};
|
|
1681
1742
|
}
|
|
1682
1743
|
const paths = changedPaths(workspacePath, remoteHead, localHead);
|
|
1683
|
-
const size = paths.length > 0 ? await diffSizeBytes(workspacePath, remoteHead, localHead, maxDiffBytes) : 0;
|
|
1744
|
+
const size = paths.length > 0 ? await (input.measureDiffSize ?? diffSizeBytes)(workspacePath, remoteHead, localHead, maxDiffBytes) : 0;
|
|
1745
|
+
input.assertStillAdmitted?.();
|
|
1684
1746
|
if (paths.length > 0 && size > maxDiffBytes && !input.allowLargeDiff) {
|
|
1685
1747
|
const classifiedMounts = classifyMounts([...selected.active, ...selected.tombstones]);
|
|
1686
1748
|
return {
|
|
@@ -1693,15 +1755,18 @@ async function synchronizeWorkspaceGit(input) {
|
|
|
1693
1755
|
diffSizeBytes: size,
|
|
1694
1756
|
affectedPaths: paths,
|
|
1695
1757
|
...classifiedMounts,
|
|
1758
|
+
...verifiedAncestorHeads ? { verifiedAncestorHeads } : {},
|
|
1696
1759
|
error: `Workspace diff exceeds the ${maxDiffBytes}-byte automatic publication limit`
|
|
1697
1760
|
};
|
|
1698
1761
|
}
|
|
1699
1762
|
if (localHead === remoteHead) {
|
|
1763
|
+
assertWorkspaceRemediationAncestry({ workspacePath, currentHead: localHead, remoteHead, requiredAncestorHeads });
|
|
1700
1764
|
const completedMounts = completedMountSelection(Boolean(input.skipMountMirror));
|
|
1701
1765
|
await input.afterWorkspacePublished?.({
|
|
1702
1766
|
publishedHead: localHead,
|
|
1703
1767
|
activeMountIds: completedMounts.activeMountIds
|
|
1704
1768
|
});
|
|
1769
|
+
input.assertStillAdmitted?.();
|
|
1705
1770
|
return {
|
|
1706
1771
|
outcome: updated ? "updated" : "no_change",
|
|
1707
1772
|
startingHead,
|
|
@@ -1712,9 +1777,11 @@ async function synchronizeWorkspaceGit(input) {
|
|
|
1712
1777
|
diffSizeBytes: size,
|
|
1713
1778
|
affectedPaths: paths,
|
|
1714
1779
|
...completedMounts,
|
|
1780
|
+
...verifiedAncestorHeads ? { verifiedAncestorHeads } : {},
|
|
1715
1781
|
...projectionWarning ? { error: projectionWarning } : {}
|
|
1716
1782
|
};
|
|
1717
1783
|
}
|
|
1784
|
+
assertWorkspaceRemediationAncestry({ workspacePath, currentHead: localHead, remoteHead, requiredAncestorHeads });
|
|
1718
1785
|
const pushArgs = [
|
|
1719
1786
|
...gitTransportSecurityArgs(input.remoteUrl, input.credentialHelper, input.credentialUsername),
|
|
1720
1787
|
"push",
|
|
@@ -1724,12 +1791,14 @@ async function synchronizeWorkspaceGit(input) {
|
|
|
1724
1791
|
pushArgs.push("origin", `HEAD:refs/heads/${WORKSPACE_GIT_BRANCH}`);
|
|
1725
1792
|
const push = gitResult(workspacePath, pushArgs);
|
|
1726
1793
|
if (push.exitCode === 0) {
|
|
1794
|
+
assertWorkspaceRemediationAncestry({ workspacePath, currentHead: localHead, remoteHead, requiredAncestorHeads });
|
|
1727
1795
|
updateIntegratedWorkspaceHead(workspacePath, localHead);
|
|
1728
1796
|
const completedMounts = completedMountSelection(Boolean(input.skipMountMirror));
|
|
1729
1797
|
await input.afterWorkspacePublished?.({
|
|
1730
1798
|
publishedHead: localHead,
|
|
1731
1799
|
activeMountIds: completedMounts.activeMountIds
|
|
1732
1800
|
});
|
|
1801
|
+
input.assertStillAdmitted?.();
|
|
1733
1802
|
return {
|
|
1734
1803
|
outcome: "pushed",
|
|
1735
1804
|
startingHead,
|
|
@@ -1740,6 +1809,7 @@ async function synchronizeWorkspaceGit(input) {
|
|
|
1740
1809
|
diffSizeBytes: size,
|
|
1741
1810
|
affectedPaths: paths,
|
|
1742
1811
|
...completedMounts,
|
|
1812
|
+
...verifiedAncestorHeads ? { verifiedAncestorHeads } : {},
|
|
1743
1813
|
...projectionWarning ? { error: projectionWarning } : {}
|
|
1744
1814
|
};
|
|
1745
1815
|
}
|
|
@@ -1765,11 +1835,14 @@ export {
|
|
|
1765
1835
|
WORKSPACE_GIT_CONFIRMED_LARGE_DIFF_PUSH_OPTION,
|
|
1766
1836
|
WORKSPACE_GIT_HYDRATED_RECEIPT,
|
|
1767
1837
|
WORKSPACE_GIT_HYDRATION_TRANSACTION,
|
|
1838
|
+
WorkspaceRemediationAncestryError,
|
|
1839
|
+
configureExistingWorkspaceGitForRemediation,
|
|
1768
1840
|
ensureWorkspaceGitClone,
|
|
1769
1841
|
hydrateWorkspaceGitMounts,
|
|
1770
1842
|
recoverWorkspaceGitHydration,
|
|
1771
1843
|
resetWorkspaceGit,
|
|
1772
1844
|
synchronizeWorkspaceGit,
|
|
1773
1845
|
workspaceGitHydrationIsCurrent,
|
|
1846
|
+
workspaceGitMountsForRemediation,
|
|
1774
1847
|
workspaceGitSyncTestHarness
|
|
1775
1848
|
};
|
package/dist/types/main.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { Database } from "bun:sqlite";
|
|
3
|
+
import type { WorkerGitIdentity } from "./git-identity";
|
|
3
4
|
import { configureGitHubRegistryAuthFiles, type PreparedPrivateAuthFileGeneration } from "./registry-auth";
|
|
4
5
|
type WorkerProjectConfig = {
|
|
5
6
|
projectId: string;
|
|
@@ -22,6 +23,53 @@ type WorkerProjectConfig = {
|
|
|
22
23
|
baseCommitHash: string;
|
|
23
24
|
}>;
|
|
24
25
|
};
|
|
26
|
+
type WorkspaceSyncTrigger = {
|
|
27
|
+
type: "connect" | "inbound_head" | "write" | "edit" | "shell_inline" | "process_terminal" | "process_cancel" | "periodic" | "manual" | "remediation" | "remediation_confirm" | "remediation_reset";
|
|
28
|
+
sessionId?: string;
|
|
29
|
+
processRunId?: string;
|
|
30
|
+
toolCallId?: string;
|
|
31
|
+
projectId?: string;
|
|
32
|
+
branchName?: string;
|
|
33
|
+
detail?: string;
|
|
34
|
+
};
|
|
35
|
+
type WorkspaceSyncResult = {
|
|
36
|
+
type: "workspace_sync";
|
|
37
|
+
attemptId: string;
|
|
38
|
+
workerLabel: string;
|
|
39
|
+
trigger: WorkspaceSyncTrigger;
|
|
40
|
+
outcome: "no_change" | "published" | "updated" | "conflict_reset" | "large_diff_blocked" | "conflict_blocked" | "reset" | "failed";
|
|
41
|
+
startingHead: string | null;
|
|
42
|
+
localHead?: string;
|
|
43
|
+
publishedHead?: string;
|
|
44
|
+
rebaseCount: number;
|
|
45
|
+
diffSizeBytes: number;
|
|
46
|
+
gitStatus: string;
|
|
47
|
+
affectedProjects: string[];
|
|
48
|
+
affectedPaths: string[];
|
|
49
|
+
activeMountIds?: string[];
|
|
50
|
+
skippedMountIds?: string[];
|
|
51
|
+
activeProjectBranchPublications?: Array<{
|
|
52
|
+
branchId: string;
|
|
53
|
+
projectId: string;
|
|
54
|
+
branchName: string;
|
|
55
|
+
}>;
|
|
56
|
+
discardedPaths: string[];
|
|
57
|
+
localChangesDiscarded: boolean;
|
|
58
|
+
conflictPaths?: string[];
|
|
59
|
+
conflictSnapshotRefs?: {
|
|
60
|
+
local: string;
|
|
61
|
+
remote: string;
|
|
62
|
+
};
|
|
63
|
+
conflictKind?: "integration_rebase" | "projection_merge";
|
|
64
|
+
verifiedAncestorHeads?: string[];
|
|
65
|
+
telemetry?: {
|
|
66
|
+
totalMs: number;
|
|
67
|
+
queueMs: number;
|
|
68
|
+
prepareMs: number;
|
|
69
|
+
synchronizeMs: number;
|
|
70
|
+
};
|
|
71
|
+
error?: string;
|
|
72
|
+
};
|
|
25
73
|
export type WorkerSessionTarget = {
|
|
26
74
|
type: "project";
|
|
27
75
|
projectId: string;
|
|
@@ -31,6 +79,208 @@ export type WorkerSessionTarget = {
|
|
|
31
79
|
ownerUserId: string;
|
|
32
80
|
rootProfile: "visible_projects" | "canonical_sync";
|
|
33
81
|
};
|
|
82
|
+
type WorkerServerMessage = {
|
|
83
|
+
type: "connected";
|
|
84
|
+
label: string;
|
|
85
|
+
workerId: string;
|
|
86
|
+
} | {
|
|
87
|
+
type: "workspace_config";
|
|
88
|
+
requestId: string;
|
|
89
|
+
projects: WorkerProjectConfig[];
|
|
90
|
+
workspaceRemoteUrl: string;
|
|
91
|
+
gitIdentity: WorkerGitIdentity;
|
|
92
|
+
githubCredential: WorkerGitHubCredential | null;
|
|
93
|
+
deferWorkspaceSyncForIncidentId?: string;
|
|
94
|
+
resetToCanonical?: boolean;
|
|
95
|
+
} | {
|
|
96
|
+
type: "sync_workspace";
|
|
97
|
+
requestId: string;
|
|
98
|
+
attemptId: string;
|
|
99
|
+
trigger: WorkspaceSyncTrigger;
|
|
100
|
+
confirmedLargeDiff?: boolean;
|
|
101
|
+
confirmationReason?: string;
|
|
102
|
+
resetToCanonical?: boolean;
|
|
103
|
+
requiredAncestorHeads?: string[];
|
|
104
|
+
} | {
|
|
105
|
+
type: "create_project_branch";
|
|
106
|
+
requestId: string;
|
|
107
|
+
branchId: string;
|
|
108
|
+
projectId: string;
|
|
109
|
+
sourceBranch: string;
|
|
110
|
+
targetBranch: string;
|
|
111
|
+
} | {
|
|
112
|
+
type: "delete_project_branch";
|
|
113
|
+
requestId: string;
|
|
114
|
+
branchId: string;
|
|
115
|
+
projectId: string;
|
|
116
|
+
branchName: string;
|
|
117
|
+
} | {
|
|
118
|
+
type: "code_list";
|
|
119
|
+
requestId: string;
|
|
120
|
+
target: Extract<WorkerSessionTarget, {
|
|
121
|
+
type: "project";
|
|
122
|
+
}>;
|
|
123
|
+
path: string;
|
|
124
|
+
} | {
|
|
125
|
+
type: "code_read";
|
|
126
|
+
requestId: string;
|
|
127
|
+
target: Extract<WorkerSessionTarget, {
|
|
128
|
+
type: "project";
|
|
129
|
+
}>;
|
|
130
|
+
path: string;
|
|
131
|
+
} | {
|
|
132
|
+
type: "sync_session_artifacts";
|
|
133
|
+
requestId: string;
|
|
134
|
+
sessionId: string;
|
|
135
|
+
} | {
|
|
136
|
+
type: "workspace_incident_updated";
|
|
137
|
+
incidentId: string | null;
|
|
138
|
+
status: "remediating" | "waiting_for_worker" | "resolved" | "confirmed" | "reset" | null;
|
|
139
|
+
originWorkerLabel?: string;
|
|
140
|
+
} | {
|
|
141
|
+
type: "exec_terminal_ack";
|
|
142
|
+
runId: string;
|
|
143
|
+
} | {
|
|
144
|
+
type: "port_forward_connect";
|
|
145
|
+
forwardId: string;
|
|
146
|
+
relayConnectionId: string;
|
|
147
|
+
workerPort: number;
|
|
148
|
+
} | {
|
|
149
|
+
type: "update_clis";
|
|
150
|
+
requestId: string;
|
|
151
|
+
workerPackageSpec: string;
|
|
152
|
+
r5dctlPackageSpec: string;
|
|
153
|
+
targetWorkerVersion: string;
|
|
154
|
+
targetR5dctlVersion: string;
|
|
155
|
+
} | {
|
|
156
|
+
type: "exec";
|
|
157
|
+
requestId: string;
|
|
158
|
+
runId: string;
|
|
159
|
+
target: WorkerSessionTarget;
|
|
160
|
+
sessionId?: string;
|
|
161
|
+
argv: string[];
|
|
162
|
+
cwd?: string;
|
|
163
|
+
env?: Record<string, string>;
|
|
164
|
+
timeoutMs?: number;
|
|
165
|
+
workspaceEffect?: "none";
|
|
166
|
+
} | {
|
|
167
|
+
type: "exec_start";
|
|
168
|
+
requestId: string;
|
|
169
|
+
runId: string;
|
|
170
|
+
target: WorkerSessionTarget;
|
|
171
|
+
sessionId: string;
|
|
172
|
+
argv: string[];
|
|
173
|
+
command: string;
|
|
174
|
+
mode: "foreground" | "detached";
|
|
175
|
+
credentialId?: string;
|
|
176
|
+
cwd?: string;
|
|
177
|
+
env?: Record<string, string>;
|
|
178
|
+
timeoutMs?: number;
|
|
179
|
+
interactive?: boolean;
|
|
180
|
+
workspaceEffect?: "none";
|
|
181
|
+
} | {
|
|
182
|
+
type: "exec_stdin";
|
|
183
|
+
requestId: string;
|
|
184
|
+
runId: string;
|
|
185
|
+
data?: string;
|
|
186
|
+
eof?: boolean;
|
|
187
|
+
} | {
|
|
188
|
+
type: "pty_open";
|
|
189
|
+
requestId: string;
|
|
190
|
+
ptyId: string;
|
|
191
|
+
target: WorkerSessionTarget;
|
|
192
|
+
cols: number;
|
|
193
|
+
rows: number;
|
|
194
|
+
command?: string;
|
|
195
|
+
env?: Record<string, string>;
|
|
196
|
+
envFiles?: Array<{
|
|
197
|
+
path: string;
|
|
198
|
+
content: string;
|
|
199
|
+
mode?: number;
|
|
200
|
+
}>;
|
|
201
|
+
} | {
|
|
202
|
+
type: "pty_input";
|
|
203
|
+
ptyId: string;
|
|
204
|
+
data: string;
|
|
205
|
+
} | {
|
|
206
|
+
type: "pty_resize";
|
|
207
|
+
ptyId: string;
|
|
208
|
+
cols: number;
|
|
209
|
+
rows: number;
|
|
210
|
+
} | {
|
|
211
|
+
type: "pty_close";
|
|
212
|
+
ptyId: string;
|
|
213
|
+
} | {
|
|
214
|
+
type: "read";
|
|
215
|
+
requestId: string;
|
|
216
|
+
target: WorkerSessionTarget;
|
|
217
|
+
sessionId?: string;
|
|
218
|
+
activePlanId?: string;
|
|
219
|
+
filePath: string;
|
|
220
|
+
offset?: number;
|
|
221
|
+
limit?: number;
|
|
222
|
+
} | {
|
|
223
|
+
type: "write";
|
|
224
|
+
requestId: string;
|
|
225
|
+
target: WorkerSessionTarget;
|
|
226
|
+
sessionId?: string;
|
|
227
|
+
activePlanId?: string;
|
|
228
|
+
filePath: string;
|
|
229
|
+
content: string;
|
|
230
|
+
} | {
|
|
231
|
+
type: "edit";
|
|
232
|
+
requestId: string;
|
|
233
|
+
target: WorkerSessionTarget;
|
|
234
|
+
sessionId?: string;
|
|
235
|
+
activePlanId?: string;
|
|
236
|
+
filePath: string;
|
|
237
|
+
edits: Array<{
|
|
238
|
+
oldText: string;
|
|
239
|
+
newText: string;
|
|
240
|
+
}>;
|
|
241
|
+
} | {
|
|
242
|
+
type: "grep";
|
|
243
|
+
requestId: string;
|
|
244
|
+
target: WorkerSessionTarget;
|
|
245
|
+
sessionId?: string;
|
|
246
|
+
activePlanId?: string;
|
|
247
|
+
pattern: string;
|
|
248
|
+
path?: string;
|
|
249
|
+
glob?: string;
|
|
250
|
+
caseSensitive?: boolean;
|
|
251
|
+
limit?: number;
|
|
252
|
+
} | {
|
|
253
|
+
type: "find";
|
|
254
|
+
requestId: string;
|
|
255
|
+
target: WorkerSessionTarget;
|
|
256
|
+
sessionId?: string;
|
|
257
|
+
activePlanId?: string;
|
|
258
|
+
pattern?: string;
|
|
259
|
+
path?: string;
|
|
260
|
+
entryType?: string;
|
|
261
|
+
limit?: number;
|
|
262
|
+
} | {
|
|
263
|
+
type: "ls";
|
|
264
|
+
requestId: string;
|
|
265
|
+
target: WorkerSessionTarget;
|
|
266
|
+
sessionId?: string;
|
|
267
|
+
activePlanId?: string;
|
|
268
|
+
path?: string;
|
|
269
|
+
limit?: number;
|
|
270
|
+
} | {
|
|
271
|
+
type: "view_file_bytes";
|
|
272
|
+
requestId: string;
|
|
273
|
+
target: WorkerSessionTarget;
|
|
274
|
+
sessionId?: string;
|
|
275
|
+
activePlanId?: string;
|
|
276
|
+
filePath: string;
|
|
277
|
+
} | {
|
|
278
|
+
type: "cancel";
|
|
279
|
+
requestId: string;
|
|
280
|
+
runId: string;
|
|
281
|
+
} | {
|
|
282
|
+
type: "ping";
|
|
283
|
+
};
|
|
34
284
|
type WorkerReadFileResult = {
|
|
35
285
|
type: "read";
|
|
36
286
|
kind: "text";
|
|
@@ -151,6 +401,7 @@ export declare const workerPtyTestHarness: {
|
|
|
151
401
|
removeEnvFiles: typeof removePtyEnvFiles;
|
|
152
402
|
resolveEnvFileReferences: typeof resolvePtyEnvFileReferences;
|
|
153
403
|
commandHasWorkspaceEffect: typeof workerCommandHasWorkspaceEffect;
|
|
404
|
+
canonicalSyncTerminalHead: typeof canonicalSyncTerminalHead;
|
|
154
405
|
ptyIsWorkspaceBusy: typeof workerPtyIsWorkspaceBusy;
|
|
155
406
|
parseLinuxForegroundBusy: typeof parseLinuxPtyForegroundBusy;
|
|
156
407
|
};
|
|
@@ -302,6 +553,64 @@ type CredentialReapContractProbe = {
|
|
|
302
553
|
type CredentialReapContractStatus = "direct" | "systemd_unverified" | "verified_systemd";
|
|
303
554
|
declare function credentialReapContractStatus(probe?: CredentialReapContractProbe): CredentialReapContractStatus;
|
|
304
555
|
declare function verifiedCredentialReapContract(probe?: CredentialReapContractProbe): boolean;
|
|
556
|
+
declare function workspaceConfigurationIncidentDeferral(input: {
|
|
557
|
+
requestedIncidentId: string | undefined;
|
|
558
|
+
activeIncidentId: string | null;
|
|
559
|
+
}): {
|
|
560
|
+
incidentId: string | null;
|
|
561
|
+
error?: Error;
|
|
562
|
+
};
|
|
563
|
+
type DeferredWorkspaceConfiguration = {
|
|
564
|
+
incidentId: string;
|
|
565
|
+
serverRefreshExpected: boolean;
|
|
566
|
+
};
|
|
567
|
+
declare function workspaceIncidentTerminalClearDisposition(input: {
|
|
568
|
+
deferredConfiguration: DeferredWorkspaceConfiguration | null;
|
|
569
|
+
clearedIncidentId: string;
|
|
570
|
+
}): "await_server_refresh" | "reconnect_for_refresh";
|
|
571
|
+
declare function workspaceIncidentTerminalRefreshFence(input: {
|
|
572
|
+
deferredConfiguration: DeferredWorkspaceConfiguration | null;
|
|
573
|
+
clearedIncidentId: string;
|
|
574
|
+
}): {
|
|
575
|
+
disposition: "await_server_refresh" | "reconnect_for_refresh";
|
|
576
|
+
deferredConfiguration: DeferredWorkspaceConfiguration;
|
|
577
|
+
};
|
|
578
|
+
declare function workspaceAutomaticSyncIsAdmitted(input: {
|
|
579
|
+
workspaceConfigured: boolean;
|
|
580
|
+
activeIncidentId: string | null;
|
|
581
|
+
deferredConfiguration: DeferredWorkspaceConfiguration | null;
|
|
582
|
+
}): boolean;
|
|
583
|
+
declare function deferredWorkspaceTargetIsAllowed(deferredConfiguration: DeferredWorkspaceConfiguration | null, activeIncidentId: string | null, target: WorkerSessionTarget): boolean;
|
|
584
|
+
declare function deferredWorkspaceSyncTriggerIsAllowed(deferredConfiguration: DeferredWorkspaceConfiguration | null, activeIncidentId: string | null, trigger: WorkspaceSyncTrigger): boolean;
|
|
585
|
+
declare function workspaceOperationsAreFenced(deferredConfiguration: DeferredWorkspaceConfiguration | null, activeIncidentId: string | null): boolean;
|
|
586
|
+
declare function workspaceCommandTransportIsAllowed(deferredConfiguration: DeferredWorkspaceConfiguration | null, activeIncidentId: string | null, transport: "exec" | "exec_start"): boolean;
|
|
587
|
+
declare function deferredCredentialTransitionMustWait(input: {
|
|
588
|
+
incidentId: string | null;
|
|
589
|
+
transitionPhase: CredentialGenerationTransitionPhase;
|
|
590
|
+
canonicalRemediationActive: boolean;
|
|
591
|
+
}): boolean;
|
|
592
|
+
declare function workspaceConfigurationIncidentSnapshotIsCurrent(capturedIncidentId: string | null, activeIncidentId: string | null): boolean;
|
|
593
|
+
declare function workspaceConfigurationResetToCanonicalIsAllowed(requested: boolean | undefined, incidentId: string | null): boolean;
|
|
594
|
+
declare function deferredWorkspaceRefreshWatchdogIsCurrent(input: {
|
|
595
|
+
capturedIncidentId: string;
|
|
596
|
+
deferredConfiguration: DeferredWorkspaceConfiguration | null;
|
|
597
|
+
activeIncidentId: string | null;
|
|
598
|
+
}): boolean;
|
|
599
|
+
declare function incidentDeferredProjectCheckouts(projects: readonly WorkerProjectConfig[]): Array<{
|
|
600
|
+
projectId: string;
|
|
601
|
+
branchName: string;
|
|
602
|
+
}>;
|
|
603
|
+
declare function deferredIncidentWorkspaceConfigurationResult(input: {
|
|
604
|
+
attemptId: string;
|
|
605
|
+
workerLabel: string;
|
|
606
|
+
head: string | null;
|
|
607
|
+
skippedMountIds: string[];
|
|
608
|
+
}): WorkspaceSyncResult;
|
|
609
|
+
declare function workspaceSyncFailureHydrationIsSafe(input: {
|
|
610
|
+
error: unknown;
|
|
611
|
+
resetToCanonical: boolean;
|
|
612
|
+
inspectCurrentHydration: () => boolean;
|
|
613
|
+
}): boolean;
|
|
305
614
|
declare function fenceUnsafeWorkspaceSyncFailure(input: {
|
|
306
615
|
hydrationCurrent: boolean;
|
|
307
616
|
invalidateExecution: () => void;
|
|
@@ -332,7 +641,24 @@ export declare const workerGitSecurityTestHarness: {
|
|
|
332
641
|
credentialReapContractStatus: typeof credentialReapContractStatus;
|
|
333
642
|
verifiedCredentialReapContract: typeof verifiedCredentialReapContract;
|
|
334
643
|
fenceUnsafeWorkspaceSyncFailure: typeof fenceUnsafeWorkspaceSyncFailure;
|
|
644
|
+
workspaceConfigurationIncidentDeferral: typeof workspaceConfigurationIncidentDeferral;
|
|
645
|
+
workspaceIncidentTerminalClearDisposition: typeof workspaceIncidentTerminalClearDisposition;
|
|
646
|
+
workspaceIncidentTerminalRefreshFence: typeof workspaceIncidentTerminalRefreshFence;
|
|
647
|
+
workspaceAutomaticSyncIsAdmitted: typeof workspaceAutomaticSyncIsAdmitted;
|
|
648
|
+
deferredWorkspaceTargetIsAllowed: typeof deferredWorkspaceTargetIsAllowed;
|
|
649
|
+
deferredWorkspaceSyncTriggerIsAllowed: typeof deferredWorkspaceSyncTriggerIsAllowed;
|
|
650
|
+
workspaceOperationsAreFenced: typeof workspaceOperationsAreFenced;
|
|
651
|
+
workspaceCommandTransportIsAllowed: typeof workspaceCommandTransportIsAllowed;
|
|
652
|
+
deferredCredentialTransitionMustWait: typeof deferredCredentialTransitionMustWait;
|
|
653
|
+
workspaceConfigurationIncidentSnapshotIsCurrent: typeof workspaceConfigurationIncidentSnapshotIsCurrent;
|
|
654
|
+
workspaceConfigurationResetToCanonicalIsAllowed: typeof workspaceConfigurationResetToCanonicalIsAllowed;
|
|
655
|
+
deferredWorkspaceRefreshWatchdogIsCurrent: typeof deferredWorkspaceRefreshWatchdogIsCurrent;
|
|
656
|
+
incidentDeferredProjectCheckouts: typeof incidentDeferredProjectCheckouts;
|
|
657
|
+
deferredIncidentWorkspaceConfigurationResult: typeof deferredIncidentWorkspaceConfigurationResult;
|
|
658
|
+
workspaceSyncFailureHydrationIsSafe: typeof workspaceSyncFailureHydrationIsSafe;
|
|
335
659
|
assertWorkerChildAdmission: typeof assertWorkerChildAdmission;
|
|
660
|
+
executeWriteFileOperation: typeof executeWriteFileOperation;
|
|
661
|
+
executeEditFileOperation: typeof executeEditFileOperation;
|
|
336
662
|
terminateCredentialBearingChildren: typeof terminateCredentialBearingChildren;
|
|
337
663
|
terminateCredentialBearingChildrenWithRetention: typeof terminateCredentialBearingChildrenWithRetention;
|
|
338
664
|
commitCredentialGeneration(prepared: PreparedPrivateAuthFileGeneration, credential: WorkerGitHubCredential | null, children: readonly {
|
|
@@ -365,6 +691,7 @@ type ResolvedWorkerSessionTarget = {
|
|
|
365
691
|
rootPath: string;
|
|
366
692
|
config?: WorkerProjectConfig;
|
|
367
693
|
};
|
|
694
|
+
declare function canonicalSyncTerminalHead(resolvedTarget: Pick<ResolvedWorkerSessionTarget, "target" | "rootPath">, readHead?: (rootPath: string) => string): string | undefined;
|
|
368
695
|
export declare function describeWorkerSessionTarget(target: WorkerSessionTarget): string;
|
|
369
696
|
export declare function resolveWorkerSessionTarget(input: {
|
|
370
697
|
target: WorkerSessionTarget;
|
|
@@ -389,6 +716,28 @@ export declare function editWorkerTextFile(branchPath: string, filePath: string,
|
|
|
389
716
|
oldText: string;
|
|
390
717
|
newText: string;
|
|
391
718
|
}>, builtInPaths?: WorkerBuiltInToolPaths): WorkerEditFileResult;
|
|
719
|
+
declare function executeWriteFileOperation(input: {
|
|
720
|
+
message: Extract<WorkerServerMessage, {
|
|
721
|
+
type: "write";
|
|
722
|
+
}>;
|
|
723
|
+
resolvedTarget: ResolvedWorkerSessionTarget;
|
|
724
|
+
baseUrl: string;
|
|
725
|
+
token: string;
|
|
726
|
+
artifactRoot: string;
|
|
727
|
+
planRoot: string;
|
|
728
|
+
assertAdmission: () => void;
|
|
729
|
+
}): Promise<WorkerWriteFileResult>;
|
|
730
|
+
declare function executeEditFileOperation(input: {
|
|
731
|
+
message: Extract<WorkerServerMessage, {
|
|
732
|
+
type: "edit";
|
|
733
|
+
}>;
|
|
734
|
+
resolvedTarget: ResolvedWorkerSessionTarget;
|
|
735
|
+
baseUrl: string;
|
|
736
|
+
token: string;
|
|
737
|
+
artifactRoot: string;
|
|
738
|
+
planRoot: string;
|
|
739
|
+
assertAdmission: () => void;
|
|
740
|
+
}): Promise<WorkerEditFileResult>;
|
|
392
741
|
export declare function grepWorkerFiles(branchPath: string, input: {
|
|
393
742
|
pattern: string;
|
|
394
743
|
path?: string;
|