@indigoai-us/hq-cloud 6.15.79 → 6.15.81
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/bin/area-ledger-migration.d.ts +13 -0
- package/dist/bin/area-ledger-migration.d.ts.map +1 -0
- package/dist/bin/area-ledger-migration.js +64 -0
- package/dist/bin/area-ledger-migration.js.map +1 -0
- package/dist/bin/area-ledger-migration.test.d.ts +2 -0
- package/dist/bin/area-ledger-migration.test.d.ts.map +1 -0
- package/dist/bin/area-ledger-migration.test.js +55 -0
- package/dist/bin/area-ledger-migration.test.js.map +1 -0
- package/dist/bin/sync-runner-company.d.ts +6 -0
- package/dist/bin/sync-runner-company.d.ts.map +1 -1
- package/dist/bin/sync-runner-company.js +21 -0
- package/dist/bin/sync-runner-company.js.map +1 -1
- package/dist/bin/sync-runner-company.test.js +112 -0
- package/dist/bin/sync-runner-company.test.js.map +1 -1
- package/dist/bin/sync-runner-events.test.js +20 -0
- package/dist/bin/sync-runner-events.test.js.map +1 -1
- package/dist/bin/sync-runner-watch-loop.d.ts +7 -0
- package/dist/bin/sync-runner-watch-loop.d.ts.map +1 -1
- package/dist/bin/sync-runner-watch-loop.js +308 -20
- package/dist/bin/sync-runner-watch-loop.js.map +1 -1
- package/dist/bin/sync-runner.d.ts +5 -0
- package/dist/bin/sync-runner.d.ts.map +1 -1
- package/dist/bin/sync-runner.js.map +1 -1
- package/dist/bin/sync-runner.test.js +144 -1
- package/dist/bin/sync-runner.test.js.map +1 -1
- package/dist/cli/share.d.ts +8 -0
- package/dist/cli/share.d.ts.map +1 -1
- package/dist/cli/share.js +213 -15
- package/dist/cli/share.js.map +1 -1
- package/dist/cli/share.test.js +461 -31
- package/dist/cli/share.test.js.map +1 -1
- package/dist/cli/sync.d.ts +30 -0
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +83 -8
- package/dist/cli/sync.js.map +1 -1
- package/dist/cli/sync.test.js +224 -0
- package/dist/cli/sync.test.js.map +1 -1
- package/dist/cli/watch-event-push-conflict.test.js +22 -11
- package/dist/cli/watch-event-push-conflict.test.js.map +1 -1
- package/dist/journal-store.test.js +42 -1
- package/dist/journal-store.test.js.map +1 -1
- package/dist/journal.d.ts +12 -1
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +103 -6
- package/dist/journal.js.map +1 -1
- package/dist/s3.d.ts +62 -0
- package/dist/s3.d.ts.map +1 -1
- package/dist/s3.js +91 -1
- package/dist/s3.js.map +1 -1
- package/dist/s3.rename-retry.test.d.ts +2 -0
- package/dist/s3.rename-retry.test.d.ts.map +1 -0
- package/dist/s3.rename-retry.test.js +153 -0
- package/dist/s3.rename-retry.test.js.map +1 -0
- package/dist/sync/area-ledger-migration.d.ts +116 -0
- package/dist/sync/area-ledger-migration.d.ts.map +1 -0
- package/dist/sync/area-ledger-migration.js +505 -0
- package/dist/sync/area-ledger-migration.js.map +1 -0
- package/dist/sync/area-ledger-migration.test.d.ts +2 -0
- package/dist/sync/area-ledger-migration.test.d.ts.map +1 -0
- package/dist/sync/area-ledger-migration.test.js +274 -0
- package/dist/sync/area-ledger-migration.test.js.map +1 -0
- package/dist/sync/feature-flags.d.ts +9 -0
- package/dist/sync/feature-flags.d.ts.map +1 -1
- package/dist/sync/feature-flags.js +19 -0
- package/dist/sync/feature-flags.js.map +1 -1
- package/dist/sync/feature-flags.test.js +11 -1
- package/dist/sync/feature-flags.test.js.map +1 -1
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +1 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/parallel-sync-coordinator.d.ts.map +1 -1
- package/dist/sync/parallel-sync-coordinator.js +19 -4
- package/dist/sync/parallel-sync-coordinator.js.map +1 -1
- package/dist/sync/parallel-sync-coordinator.test.js +59 -0
- package/dist/sync/parallel-sync-coordinator.test.js.map +1 -1
- package/dist/sync/reconcile-cursor.d.ts +97 -0
- package/dist/sync/reconcile-cursor.d.ts.map +1 -0
- package/dist/sync/reconcile-cursor.js +215 -0
- package/dist/sync/reconcile-cursor.js.map +1 -0
- package/dist/sync/reconcile-cursor.test.d.ts +2 -0
- package/dist/sync/reconcile-cursor.test.d.ts.map +1 -0
- package/dist/sync/reconcile-cursor.test.js +139 -0
- package/dist/sync/reconcile-cursor.test.js.map +1 -0
- package/dist/sync/state-store.d.ts +37 -0
- package/dist/sync/state-store.d.ts.map +1 -1
- package/dist/sync/state-store.js +109 -1
- package/dist/sync/state-store.js.map +1 -1
- package/dist/sync/sync-work.d.ts +2 -1
- package/dist/sync/sync-work.d.ts.map +1 -1
- package/dist/sync/sync-work.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/vault-client.d.ts +9 -2
- package/dist/vault-client.d.ts.map +1 -1
- package/dist/vault-client.js +3 -2
- package/dist/vault-client.js.map +1 -1
- package/dist/vault-client.test.js +26 -0
- package/dist/vault-client.test.js.map +1 -1
- package/package.json +3 -2
package/dist/cli/share.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { type CompanyTombstone } from "./tombstones.js";
|
|
|
12
12
|
import { type ScopePrefixInput } from "../prefix-coalesce.js";
|
|
13
13
|
import { type TransferSemaphore } from "../sync-core.js";
|
|
14
14
|
import { type RegisterCompanySkillResult } from "../vault-client.js";
|
|
15
|
+
import { type ReconcileApplyCheckpoint } from "../sync/reconcile-cursor.js";
|
|
15
16
|
/**
|
|
16
17
|
* Local-only ephemeral artifacts: conflict-side files written whenever a
|
|
17
18
|
* 3-way merge preserves the displaced side for inspection. Depending on the
|
|
@@ -446,6 +447,11 @@ export interface ShareOptions {
|
|
|
446
447
|
* the network. See the consult in the Stage-2 classification pass.
|
|
447
448
|
*/
|
|
448
449
|
fileTombstones?: ReadonlyMap<string, CompanyTombstone>;
|
|
450
|
+
/**
|
|
451
|
+
* Opt-in bounded reconcile apply checkpoint. It is recorded only after
|
|
452
|
+
* `finalizeShareJournal()` has durably committed this slice's outcomes.
|
|
453
|
+
*/
|
|
454
|
+
reconcileApply?: ReconcileApplyCheckpoint;
|
|
449
455
|
/**
|
|
450
456
|
* What to do when a path the caller EXPLICITLY named cannot be shipped —
|
|
451
457
|
* it does not resolve under any base, or it resolves outside the company
|
|
@@ -481,6 +487,8 @@ export interface CompanySkillRegistrationRequest {
|
|
|
481
487
|
companySlug: string;
|
|
482
488
|
path: string;
|
|
483
489
|
content: string;
|
|
490
|
+
/** These exact bytes have successfully landed in the company vault. */
|
|
491
|
+
landed?: boolean;
|
|
484
492
|
}
|
|
485
493
|
export type CompanySkillRegistrar = (input: CompanySkillRegistrationRequest) => Promise<RegisterCompanySkillResult>;
|
|
486
494
|
export declare class UnregisteredCompanySkillError extends Error {
|
package/dist/cli/share.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"share.d.ts","sourceRoot":"","sources":["../../src/cli/share.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAe,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"share.d.ts","sourceRoot":"","sources":["../../src/cli/share.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/share.js
CHANGED
|
@@ -10,7 +10,7 @@ import * as path from "path";
|
|
|
10
10
|
import { resolveEntityContext, isExpiringSoon, refreshEntityContext } from "../context.js";
|
|
11
11
|
import { createSyncProgressRecorder } from "../sync-progress.js";
|
|
12
12
|
import { localPathForVaultKey, vaultKeyForLocalPath } from "../local-path-codec.js";
|
|
13
|
-
import { uploadFile, uploadSymlink, toPosixKey, headRemoteFile, readVerifiedRemoteSymlinkTarget, deleteRemoteFile, downloadFile, primeObjectTransport, primeUploads, WindowsSymlinkPrivilegeError, WINDOWS_SYMLINK_PRIVILEGE_REMEDY, } from "../s3.js";
|
|
13
|
+
import { uploadFile, uploadSymlink, toPosixKey, headRemoteFile, readVerifiedRemoteSymlinkTarget, deleteRemoteFile, downloadFile, primeObjectTransport, primeUploads, WindowsSymlinkPrivilegeError, WINDOWS_SYMLINK_PRIVILEGE_REMEDY, WindowsRenameBlockedError, WINDOWS_RENAME_BLOCKED_REMEDY, renameOrRaiseWindowsBlocked, } from "../s3.js";
|
|
14
14
|
import * as crypto from "crypto";
|
|
15
15
|
import { readJournal, writeJournal, hashFile, hashSymlinkTarget, updateEntry, removeEntry, isTombstone, normalizeEtag, PERSONAL_VAULT_JOURNAL_SLUG, migratePersonalVaultJournal, migrateToV2, } from "../journal.js";
|
|
16
16
|
import { createIgnoreFilter, hasControlCharacters, isExpectedIgnore, isWithinSizeLimit, } from "../ignore.js";
|
|
@@ -26,6 +26,7 @@ import { isCloudAuthoritative } from "../lib/cloud-authoritative.js";
|
|
|
26
26
|
import { VaultAuthError, VaultClient, } from "../vault-client.js";
|
|
27
27
|
import { describeError } from "../lib/describe-error.js";
|
|
28
28
|
import { readlinkOrNull } from "../lib/readlink-safe.js";
|
|
29
|
+
import { checkpointReconcileApply } from "../sync/reconcile-cursor.js";
|
|
29
30
|
/**
|
|
30
31
|
* Push-side fresh-collision convergence probe.
|
|
31
32
|
*
|
|
@@ -686,6 +687,20 @@ export async function share(options) {
|
|
|
686
687
|
await executeDeletes(run, plans.deletePlan, plans.decommissionPlan, counters, filesRefusedStalePaths, pathResults, !uploadResult.hadUploadFailure && uploadResult.workerErrors.length === 0);
|
|
687
688
|
finalizeShareJournal(run);
|
|
688
689
|
throwUploadWorkerErrors(uploadResult.workerErrors);
|
|
690
|
+
// A reconcile cursor is an all-or-nothing boundary for this bounded apply
|
|
691
|
+
// slice. Upload and delete errors are intentionally reported per-path so an
|
|
692
|
+
// ordinary runner can continue, but none of those retryable outcomes may
|
|
693
|
+
// move the cursor beyond the failed mutation.
|
|
694
|
+
if (!uploadResult.hadUploadFailure &&
|
|
695
|
+
uploadResult.workerErrors.length === 0 &&
|
|
696
|
+
!pathResults.some((result) => result.status === "refused")) {
|
|
697
|
+
checkpointReconcileApply(options.reconcileApply, [
|
|
698
|
+
...plans.pushPlan.items.map((item) => item.relativePath),
|
|
699
|
+
...plans.deletePlan.toDelete.map((item) => item.key),
|
|
700
|
+
...plans.deletePlan.toTombstone,
|
|
701
|
+
...plans.decommissionPlan,
|
|
702
|
+
]);
|
|
703
|
+
}
|
|
689
704
|
return buildShareResult(run, counters, filesRefusedStalePaths, conflictPaths, pathResults, false);
|
|
690
705
|
}
|
|
691
706
|
/**
|
|
@@ -899,7 +914,11 @@ function skillRegistrarForRun(run) {
|
|
|
899
914
|
if (!run.vaultConfig)
|
|
900
915
|
return undefined;
|
|
901
916
|
const client = new VaultClient(run.vaultConfig);
|
|
902
|
-
return ({ companySlug, path: skillPath, content }) => client.registerCompanySkill(companySlug, {
|
|
917
|
+
return ({ companySlug, path: skillPath, content, landed }) => client.registerCompanySkill(companySlug, {
|
|
918
|
+
path: skillPath,
|
|
919
|
+
content,
|
|
920
|
+
...(landed === true ? { landed: true } : {}),
|
|
921
|
+
});
|
|
903
922
|
}
|
|
904
923
|
function assertValidSkillRegistration(result, expectedPath) {
|
|
905
924
|
const stampedUid = parseRegisteredCompanySkillUid(result.content);
|
|
@@ -943,18 +962,106 @@ async function registerOneCompanySkill(run, entry, registrar) {
|
|
|
943
962
|
async function preflightCompanySkillIdentities(run, entries) {
|
|
944
963
|
if (run.options.personalMode === true || run.ctx.uid.startsWith("prs_"))
|
|
945
964
|
return;
|
|
946
|
-
const
|
|
947
|
-
CANONICAL_COMPANY_SKILL_RE.test(entry.relativePath)
|
|
948
|
-
|
|
949
|
-
|
|
965
|
+
const canonical = entries.filter((entry) => entry.kind === "file" &&
|
|
966
|
+
CANONICAL_COMPANY_SKILL_RE.test(entry.relativePath));
|
|
967
|
+
const unstamped = canonical.filter((entry) => !parseRegisteredCompanySkillUid(fs.readFileSync(entry.absolutePath, "utf8")));
|
|
968
|
+
const pending = canonical.filter((entry) => {
|
|
969
|
+
const journalEntry = run.journal.files[entry.relativePath];
|
|
970
|
+
return (journalEntry?.skillMetadataPending === true &&
|
|
971
|
+
journalEntry.hash === hashFile(entry.absolutePath));
|
|
972
|
+
});
|
|
973
|
+
if (unstamped.length === 0 && pending.length === 0)
|
|
950
974
|
return;
|
|
951
975
|
const registrar = skillRegistrarForRun(run);
|
|
952
976
|
if (!registrar) {
|
|
953
|
-
|
|
977
|
+
if (unstamped.length > 0) {
|
|
978
|
+
throw new UnregisteredCompanySkillError(unstamped.map((entry) => entry.relativePath));
|
|
979
|
+
}
|
|
980
|
+
return;
|
|
954
981
|
}
|
|
955
982
|
for (const entry of unstamped) {
|
|
956
983
|
await registerOneCompanySkill(run, entry, registrar);
|
|
957
984
|
}
|
|
985
|
+
for (const entry of pending) {
|
|
986
|
+
const journalEntry = run.journal.files[entry.relativePath];
|
|
987
|
+
run.options.onHeartbeat?.();
|
|
988
|
+
const remote = await headRemoteFile(run.ctx, entry.relativePath);
|
|
989
|
+
if (!remote) {
|
|
990
|
+
// The upload this marker referred to no longer exists. Drop the stale
|
|
991
|
+
// baseline so the normal planner cannot skip the local file as unchanged
|
|
992
|
+
// and will upload it again on this pass.
|
|
993
|
+
delete run.journal.files[entry.relativePath];
|
|
994
|
+
flushShareJournal(run);
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
if (!journalEntry?.remoteEtag ||
|
|
998
|
+
normalizeEtag(remote.etag) !== normalizeEtag(journalEntry.remoteEtag)) {
|
|
999
|
+
// The successful PUT this marker describes is no longer the live remote
|
|
1000
|
+
// object. Reconcile the current remote bytes instead of stranding the old
|
|
1001
|
+
// marker behind skipUnchanged; the backend independently revalidates this
|
|
1002
|
+
// exact content against S3 before accepting its metadata.
|
|
1003
|
+
// Invalidate the stale baseline before any network work. If recovery
|
|
1004
|
+
// fails, the next pass must still see a real divergence rather than
|
|
1005
|
+
// classifying the local file as unchanged forever.
|
|
1006
|
+
delete run.journal.files[entry.relativePath];
|
|
1007
|
+
flushShareJournal(run);
|
|
1008
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "hq-skill-metadata-"));
|
|
1009
|
+
const tempFile = path.join(tempDir, "SKILL.md");
|
|
1010
|
+
try {
|
|
1011
|
+
await downloadFile(run.ctx, entry.relativePath, tempFile);
|
|
1012
|
+
await reconcileLandedCompanySkill(run, entry.relativePath, fs.readFileSync(tempFile, "utf8"));
|
|
1013
|
+
}
|
|
1014
|
+
finally {
|
|
1015
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
1016
|
+
}
|
|
1017
|
+
continue;
|
|
1018
|
+
}
|
|
1019
|
+
const landedBytes = fs.readFileSync(entry.absolutePath);
|
|
1020
|
+
const landedHash = crypto
|
|
1021
|
+
.createHash("sha256")
|
|
1022
|
+
.update(landedBytes)
|
|
1023
|
+
.digest("hex");
|
|
1024
|
+
if (landedHash !== journalEntry.hash) {
|
|
1025
|
+
// The editor saved after this entry was classified but before the
|
|
1026
|
+
// remote proof returned. Reconcile only the single local snapshot that
|
|
1027
|
+
// produced the journaled upload; the newer edit belongs to the planner.
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
await reconcileLandedCompanySkill(run, entry.relativePath, landedBytes.toString("utf8"));
|
|
1031
|
+
delete run.journal.files[entry.relativePath]?.skillMetadataPending;
|
|
1032
|
+
checkpointShareJournal(run);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Reconcile metadata only after the canonical bytes have landed. Identity
|
|
1037
|
+
* reservation happens before upload; tags and other source-authored metadata
|
|
1038
|
+
* must not become authoritative until the S3 write succeeds.
|
|
1039
|
+
*/
|
|
1040
|
+
async function reconcileLandedCompanySkill(run, relativePath, content) {
|
|
1041
|
+
if (run.options.personalMode === true ||
|
|
1042
|
+
run.ctx.uid.startsWith("prs_") ||
|
|
1043
|
+
!CANONICAL_COMPANY_SKILL_RE.test(relativePath)) {
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
const registrar = skillRegistrarForRun(run);
|
|
1047
|
+
if (!registrar) {
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
const localUid = parseRegisteredCompanySkillUid(content);
|
|
1051
|
+
if (!localUid) {
|
|
1052
|
+
throw new UnregisteredCompanySkillError([relativePath]);
|
|
1053
|
+
}
|
|
1054
|
+
run.options.onHeartbeat?.();
|
|
1055
|
+
const result = await registrar({
|
|
1056
|
+
companySlug: run.ctx.slug,
|
|
1057
|
+
path: relativePath,
|
|
1058
|
+
content,
|
|
1059
|
+
landed: true,
|
|
1060
|
+
});
|
|
1061
|
+
assertValidSkillRegistration(result, relativePath);
|
|
1062
|
+
if (result.skillUid !== localUid) {
|
|
1063
|
+
throw new Error(`Skill registration returned identity '${result.skillUid}' for '${relativePath}', but the landed file is stamped '${localUid}'.`);
|
|
1064
|
+
}
|
|
958
1065
|
}
|
|
959
1066
|
async function buildSharePlans(run) {
|
|
960
1067
|
const collected = collectFiles(run.paths, run.hqRoot, run.syncRoot, run.shouldSync, {
|
|
@@ -1324,12 +1431,41 @@ async function executeUploads(run, pushPlan, counters, conflictPaths) {
|
|
|
1324
1431
|
}
|
|
1325
1432
|
}
|
|
1326
1433
|
if (freshContentConverged) {
|
|
1434
|
+
// The equality probe is an await boundary. Confirm that the local body
|
|
1435
|
+
// still matches the bytes we proved are already remote before recording
|
|
1436
|
+
// convergence or reconciling source-authored metadata.
|
|
1437
|
+
const afterProbe = refreshUploadItem();
|
|
1438
|
+
if (afterProbe === null)
|
|
1439
|
+
return;
|
|
1440
|
+
if (!uploadBodyMatchesPlan(item, afterProbe)) {
|
|
1441
|
+
await restartForChangedBody(afterProbe);
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
const shouldReconcileSkill = item.kind === "file" &&
|
|
1445
|
+
CANONICAL_COMPANY_SKILL_RE.test(relativePath) &&
|
|
1446
|
+
skillRegistrarForRun(run) !== undefined;
|
|
1447
|
+
const skillBytes = shouldReconcileSkill
|
|
1448
|
+
? fs.readFileSync(absolutePath)
|
|
1449
|
+
: undefined;
|
|
1450
|
+
if (skillBytes !== undefined &&
|
|
1451
|
+
crypto.createHash("sha256").update(skillBytes).digest("hex") !== localHash) {
|
|
1452
|
+
// The editor saved after the equality proof. Re-run the normal
|
|
1453
|
+
// remote decision for those new bytes rather than claiming they have
|
|
1454
|
+
// already landed and letting their metadata get ahead of S3.
|
|
1455
|
+
const afterSkillRead = refreshUploadItem();
|
|
1456
|
+
if (afterSkillRead === null)
|
|
1457
|
+
return;
|
|
1458
|
+
await restartForChangedBody(afterSkillRead);
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
const skillContent = skillBytes?.toString("utf8");
|
|
1327
1462
|
const lstat = fs.lstatSync(absolutePath);
|
|
1328
1463
|
updateEntry(run.journal, relativePath, localHash, lstat.size, "up", absolutePath, {
|
|
1329
1464
|
remoteEtag: remoteMeta.etag,
|
|
1330
1465
|
mtimeMs: lstat.mtimeMs,
|
|
1331
1466
|
ctimeMs: ctimeToStamp(item.kind === "file" ? item.statAtHash : undefined, lstat),
|
|
1332
1467
|
kind: item.kind,
|
|
1468
|
+
skillMetadataPending: skillContent !== undefined,
|
|
1333
1469
|
});
|
|
1334
1470
|
// Same checkpoint contract as an actual upload. After repeated
|
|
1335
1471
|
// interrupted passes most of a large vault is already present remotely
|
|
@@ -1337,6 +1473,14 @@ async function executeUploads(run, pushPlan, counters, conflictPaths) {
|
|
|
1337
1473
|
// through performUpload. Without this, that pass could reconcile
|
|
1338
1474
|
// hundreds of thousands of entries purely in memory, be interrupted,
|
|
1339
1475
|
// and persist none of them — the exact loop this change exists to end.
|
|
1476
|
+
if (skillContent !== undefined) {
|
|
1477
|
+
// This is the crash-recovery path for a PUT that completed before its
|
|
1478
|
+
// journal row was persisted. Make the retry marker durable before the
|
|
1479
|
+
// registry call so another interruption remains recoverable.
|
|
1480
|
+
flushShareJournal(run);
|
|
1481
|
+
await reconcileLandedCompanySkill(run, relativePath, skillContent);
|
|
1482
|
+
delete run.journal.files[relativePath]?.skillMetadataPending;
|
|
1483
|
+
}
|
|
1340
1484
|
checkpointShareJournal(run);
|
|
1341
1485
|
run.emit({ type: "reconciled", path: relativePath, direction: "push" });
|
|
1342
1486
|
counters.filesSkipped++;
|
|
@@ -1437,10 +1581,24 @@ async function executeUploads(run, pushPlan, counters, conflictPaths) {
|
|
|
1437
1581
|
const size = isSymlinkUpload ? 0 : lstat.size;
|
|
1438
1582
|
const mtimeMs = lstat.mtimeMs;
|
|
1439
1583
|
const ctimeMs = ctimeToStamp(item.kind === "file" ? item.statAtHash : undefined, lstat);
|
|
1584
|
+
// Capture the candidate metadata bytes immediately before uploadFile's
|
|
1585
|
+
// own synchronous read. If an editor saves while the network request is
|
|
1586
|
+
// in flight, the comparison below suppresses reconciliation; that newer
|
|
1587
|
+
// version will upload and reconcile on the next pass.
|
|
1588
|
+
const skillContentAtPut = !isSymlinkUpload && CANONICAL_COMPANY_SKILL_RE.test(relativePath)
|
|
1589
|
+
? fs.readFileSync(absolutePath, "utf8")
|
|
1590
|
+
: undefined;
|
|
1440
1591
|
const { etag } = isSymlinkUpload
|
|
1441
1592
|
? await uploadSymlink(run.ctx, item.target, relativePath, run.options.author, pc)
|
|
1442
1593
|
: await uploadFile(run.ctx, absolutePath, relativePath, run.options.author, pc);
|
|
1443
|
-
updateEntry(run.journal, relativePath, localHash, size, "up", absolutePath, {
|
|
1594
|
+
updateEntry(run.journal, relativePath, localHash, size, "up", absolutePath, {
|
|
1595
|
+
remoteEtag: etag,
|
|
1596
|
+
mtimeMs,
|
|
1597
|
+
ctimeMs,
|
|
1598
|
+
kind: item.kind,
|
|
1599
|
+
skillMetadataPending: skillContentAtPut !== undefined &&
|
|
1600
|
+
skillRegistrarForRun(run) !== undefined,
|
|
1601
|
+
});
|
|
1444
1602
|
if (run.message) {
|
|
1445
1603
|
run.journal.files[relativePath] = {
|
|
1446
1604
|
...run.journal.files[relativePath],
|
|
@@ -1449,9 +1607,25 @@ async function executeUploads(run, pushPlan, counters, conflictPaths) {
|
|
|
1449
1607
|
}
|
|
1450
1608
|
counters.filesUploaded++;
|
|
1451
1609
|
counters.bytesUploaded += size;
|
|
1452
|
-
//
|
|
1453
|
-
//
|
|
1454
|
-
|
|
1610
|
+
// A landed company skill needs a durable retry marker before the registry
|
|
1611
|
+
// call. The ordinary cadence is intentionally sparse for large vaults,
|
|
1612
|
+
// but losing this row can strand tags after a crash between PUT and
|
|
1613
|
+
// reconciliation.
|
|
1614
|
+
if (run.journal.files[relativePath]?.skillMetadataPending === true) {
|
|
1615
|
+
flushShareJournal(run);
|
|
1616
|
+
}
|
|
1617
|
+
else {
|
|
1618
|
+
// Strictly after the PUT returned and the entry was applied, so an
|
|
1619
|
+
// interrupted pass can only ever re-upload a file, never skip one.
|
|
1620
|
+
checkpointShareJournal(run);
|
|
1621
|
+
}
|
|
1622
|
+
if (skillContentAtPut !== undefined &&
|
|
1623
|
+
skillRegistrarForRun(run) !== undefined &&
|
|
1624
|
+
fs.readFileSync(absolutePath, "utf8") === skillContentAtPut) {
|
|
1625
|
+
await reconcileLandedCompanySkill(run, relativePath, skillContentAtPut);
|
|
1626
|
+
delete run.journal.files[relativePath]?.skillMetadataPending;
|
|
1627
|
+
checkpointShareJournal(run);
|
|
1628
|
+
}
|
|
1455
1629
|
run.emit({
|
|
1456
1630
|
type: "progress",
|
|
1457
1631
|
path: relativePath,
|
|
@@ -1635,8 +1809,12 @@ async function writePushConflictMirror(run, item, remoteHash, preserved) {
|
|
|
1635
1809
|
// `keep` has one meaning in both directions: cloud wins the working
|
|
1636
1810
|
// name while the displaced local body remains recoverable beside it.
|
|
1637
1811
|
// Rename first, then reuse the ordinary tested download path for the
|
|
1638
|
-
// replacement instead of hand-rolling a swap around an ad-hoc GET.
|
|
1639
|
-
|
|
1812
|
+
// replacement instead of hand-rolling a swap around an ad-hoc GET. A
|
|
1813
|
+
// transient Windows sharing violation on the move-aside surfaces as
|
|
1814
|
+
// WindowsRenameBlockedError so the catch below downgrades it to a
|
|
1815
|
+
// deliberate skip; nothing has moved yet, so the skip strands nothing
|
|
1816
|
+
// (Sentry HQ-DESKTOP-54).
|
|
1817
|
+
renameOrRaiseWindowsBlocked(item.absolutePath, conflictAbs);
|
|
1640
1818
|
localMovedAside = true;
|
|
1641
1819
|
const downloaded = await downloadFile(run.ctx, item.relativePath, item.absolutePath);
|
|
1642
1820
|
remoteAdopted = true;
|
|
@@ -1691,6 +1869,11 @@ async function writePushConflictMirror(run, item, remoteHash, preserved) {
|
|
|
1691
1869
|
localMovedAside = false;
|
|
1692
1870
|
}
|
|
1693
1871
|
catch (rollbackErr) {
|
|
1872
|
+
// A rollback failure is NOT a benign skip even when the underlying
|
|
1873
|
+
// rename refusal is transient: the local body has already been moved to
|
|
1874
|
+
// `conflictAbs` and could not be restored, so the original working path
|
|
1875
|
+
// is now absent. Reporting success here would let a later pass read that
|
|
1876
|
+
// absence as a deletion. Keep it on the error channel (Codex PR #436).
|
|
1694
1877
|
run.emit({
|
|
1695
1878
|
type: "error",
|
|
1696
1879
|
path: item.relativePath,
|
|
@@ -1702,7 +1885,19 @@ async function writePushConflictMirror(run, item, remoteHash, preserved) {
|
|
|
1702
1885
|
throw mirrorErr;
|
|
1703
1886
|
if (mirrorErr instanceof JournalCheckpointError)
|
|
1704
1887
|
throw mirrorErr;
|
|
1705
|
-
if (mirrorErr instanceof
|
|
1888
|
+
if (mirrorErr instanceof WindowsRenameBlockedError) {
|
|
1889
|
+
// The local move-aside could not complete because a program is holding
|
|
1890
|
+
// the file open. Emit the deliberate skip (never type:"error") so the
|
|
1891
|
+
// push stays complete and the one-shot runner exits 0; nothing was moved
|
|
1892
|
+
// (localMovedAside is false when the preserve rename threw), so the
|
|
1893
|
+
// conflict simply re-fires next pass (Sentry HQ-DESKTOP-54, second path).
|
|
1894
|
+
run.emit({
|
|
1895
|
+
type: "skip-rename-blocked",
|
|
1896
|
+
path: item.relativePath,
|
|
1897
|
+
remedy: WINDOWS_RENAME_BLOCKED_REMEDY,
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
else if (mirrorErr instanceof WindowsSymlinkPrivilegeError) {
|
|
1706
1901
|
// The remote symlink record cannot be materialized to a conflict mirror
|
|
1707
1902
|
// on this unprivileged Windows host. Emit the deliberate skip (never
|
|
1708
1903
|
// type:"error") so the push stays complete and the runner exits 0
|
|
@@ -1876,7 +2071,7 @@ async function executeDeletes(run, deletePlan, decommissionPlan, counters, files
|
|
|
1876
2071
|
run.emit({
|
|
1877
2072
|
type: "error",
|
|
1878
2073
|
path: relativePath,
|
|
1879
|
-
message: `tombstone unlink failed: ${
|
|
2074
|
+
message: `tombstone unlink failed: ${describeError(err)}`,
|
|
1880
2075
|
});
|
|
1881
2076
|
continue;
|
|
1882
2077
|
}
|
|
@@ -2295,6 +2490,9 @@ function defaultConsoleLogger(event) {
|
|
|
2295
2490
|
else if (event.type === "skip-symlink-privilege") {
|
|
2296
2491
|
console.warn(` ! ${event.path} skipped — could not create the symbolic link on this Windows host (missing privilege). ${event.remedy}`);
|
|
2297
2492
|
}
|
|
2493
|
+
else if (event.type === "skip-rename-blocked") {
|
|
2494
|
+
console.warn(` ! ${event.path} skipped — another program on this PC is holding the file open, so HQ could not replace it yet. ${event.remedy}`);
|
|
2495
|
+
}
|
|
2298
2496
|
else if (event.type === "ignore-excluded") {
|
|
2299
2497
|
// The "not silent" surface: an ignore rule dropped content that doesn't
|
|
2300
2498
|
// look like expected build/VCS/cache noise, so it never reached the vault.
|