@indigoai-us/hq-cloud 6.15.91 → 6.15.92
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/sync-runner-company.d.ts.map +1 -1
- package/dist/bin/sync-runner-company.js +4 -0
- package/dist/bin/sync-runner-company.js.map +1 -1
- package/dist/bin/sync-runner-company.test.js +11 -8
- package/dist/bin/sync-runner-company.test.js.map +1 -1
- package/dist/cli/share.d.ts +5 -0
- package/dist/cli/share.d.ts.map +1 -1
- package/dist/cli/share.js +24 -10
- package/dist/cli/share.js.map +1 -1
- package/dist/cli/share.test.js +141 -1
- package/dist/cli/share.test.js.map +1 -1
- package/dist/journal-store.test.js +65 -1
- package/dist/journal-store.test.js.map +1 -1
- package/dist/journal.d.ts +9 -0
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +29 -0
- package/dist/journal.js.map +1 -1
- package/dist/sync/area-ledger-migration.d.ts +6 -0
- package/dist/sync/area-ledger-migration.d.ts.map +1 -1
- package/dist/sync/area-ledger-migration.js +25 -0
- package/dist/sync/area-ledger-migration.js.map +1 -1
- package/dist/sync/area-ledger.d.ts +8 -0
- package/dist/sync/area-ledger.d.ts.map +1 -1
- package/dist/sync/area-ledger.js +71 -23
- package/dist/sync/area-ledger.js.map +1 -1
- package/dist/sync/area-ledger.test.js +32 -0
- package/dist/sync/area-ledger.test.js.map +1 -1
- package/dist/sync/area-resolver.d.ts +8 -0
- package/dist/sync/area-resolver.d.ts.map +1 -1
- package/dist/sync/area-resolver.js +37 -0
- package/dist/sync/area-resolver.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/share.test.js
CHANGED
|
@@ -65,8 +65,9 @@ import * as readline from "readline";
|
|
|
65
65
|
import { share, ServerOwnedPushPathsError, UnreachablePushPathsError, UnregisteredCompanySkillError, currentUploadBytes, parseRegisteredCompanySkillUid, _testing as shareTesting, } from "./share.js";
|
|
66
66
|
import { deleteRemoteFile, downloadFile, headRemoteFile, primeObjectTransport, primeUploads, uploadFile, uploadSymlink, WindowsSymlinkPrivilegeError, } from "../s3.js";
|
|
67
67
|
import { VaultAuthError, } from "../vault-client.js";
|
|
68
|
-
import { hashFile, readJournal, writeJournal } from "../journal.js";
|
|
68
|
+
import { AreaLedgerMigration, closeCachedAreaJournalMigration, hashFile, openJournalStateStoreForMigration, readJournal, readJournalScoped, setAreaLedgerMigrationTestHooksForTest, writeJournal, } from "../journal.js";
|
|
69
69
|
import { ReconcileCursorStore } from "../sync/reconcile-cursor.js";
|
|
70
|
+
import { AreaResolver } from "../sync/area-resolver.js";
|
|
70
71
|
/**
|
|
71
72
|
* Read a journal the way production does.
|
|
72
73
|
*
|
|
@@ -3799,6 +3800,78 @@ describe("share", () => {
|
|
|
3799
3800
|
expect(result.filesDeleted).toBe(1);
|
|
3800
3801
|
expect(deleteRemoteFile).toHaveBeenCalledWith(expect.anything(), "vanished.md");
|
|
3801
3802
|
});
|
|
3803
|
+
it("defers unscoped delete and exclusion maintenance until the next full personal pass", async () => {
|
|
3804
|
+
const current = path.join(tmpDir, "personal", "current.md");
|
|
3805
|
+
fs.mkdirSync(path.dirname(current), { recursive: true });
|
|
3806
|
+
fs.writeFileSync(current, "current");
|
|
3807
|
+
const journalPath = path.join(stateDir, "sync-journal.personal.json");
|
|
3808
|
+
seedJournalAt(journalPath, {
|
|
3809
|
+
version: "2",
|
|
3810
|
+
lastSync: "",
|
|
3811
|
+
pulls: [],
|
|
3812
|
+
files: {
|
|
3813
|
+
"personal/current.md": {
|
|
3814
|
+
hash: hashFile(current),
|
|
3815
|
+
size: fs.statSync(current).size,
|
|
3816
|
+
syncedAt: new Date().toISOString(),
|
|
3817
|
+
direction: "up",
|
|
3818
|
+
remoteEtag: "current-etag",
|
|
3819
|
+
kind: "file",
|
|
3820
|
+
},
|
|
3821
|
+
".claude/worktrees/stale.md": {
|
|
3822
|
+
hash: "stale",
|
|
3823
|
+
size: 1,
|
|
3824
|
+
syncedAt: new Date().toISOString(),
|
|
3825
|
+
direction: "up",
|
|
3826
|
+
remoteEtag: "stale-etag",
|
|
3827
|
+
kind: "file",
|
|
3828
|
+
},
|
|
3829
|
+
"personal/vanished.md": {
|
|
3830
|
+
hash: "vanished",
|
|
3831
|
+
size: 1,
|
|
3832
|
+
syncedAt: new Date().toISOString(),
|
|
3833
|
+
direction: "up",
|
|
3834
|
+
remoteEtag: "vanished-etag",
|
|
3835
|
+
kind: "file",
|
|
3836
|
+
localDeleteIntent: deleteIntent("vanished-etag", "vanished"),
|
|
3837
|
+
},
|
|
3838
|
+
},
|
|
3839
|
+
});
|
|
3840
|
+
const context = makeEntityContext({ uid: "prs_personal", slug: "personal" });
|
|
3841
|
+
const scopedEvents = [];
|
|
3842
|
+
await share({
|
|
3843
|
+
paths: [current],
|
|
3844
|
+
hqRoot: tmpDir,
|
|
3845
|
+
entityContext: context,
|
|
3846
|
+
personalMode: true,
|
|
3847
|
+
scopedJournal: true,
|
|
3848
|
+
deleteScopeRoots: ["personal/current.md"],
|
|
3849
|
+
propagateDeletes: true,
|
|
3850
|
+
propagateDeletePolicy: "owned-only",
|
|
3851
|
+
skipUnchanged: true,
|
|
3852
|
+
onEvent: (event) => scopedEvents.push(event),
|
|
3853
|
+
});
|
|
3854
|
+
expect(deleteRemoteFile).not.toHaveBeenCalledWith(expect.anything(), "personal/vanished.md");
|
|
3855
|
+
expect(scopedEvents.some((event) => event.type === "personal-vault-journal-pruned"))
|
|
3856
|
+
.toBe(false);
|
|
3857
|
+
expect(readJournal("personal").files[".claude/worktrees/stale.md"]).toBeDefined();
|
|
3858
|
+
const fullEvents = [];
|
|
3859
|
+
await share({
|
|
3860
|
+
paths: [tmpDir],
|
|
3861
|
+
hqRoot: tmpDir,
|
|
3862
|
+
entityContext: context,
|
|
3863
|
+
personalMode: true,
|
|
3864
|
+
propagateDeletes: true,
|
|
3865
|
+
propagateDeletePolicy: "owned-only",
|
|
3866
|
+
skipUnchanged: true,
|
|
3867
|
+
onEvent: (event) => fullEvents.push(event),
|
|
3868
|
+
});
|
|
3869
|
+
expect(deleteRemoteFile).toHaveBeenCalledWith(expect.anything(), "personal/vanished.md");
|
|
3870
|
+
expect(fullEvents.some((event) => event.type === "personal-vault-journal-pruned"))
|
|
3871
|
+
.toBe(true);
|
|
3872
|
+
expect(readJournal("personal").files[".claude/worktrees/stale.md"]).toBeUndefined();
|
|
3873
|
+
expect(readJournal("personal").files["personal/vanished.md"]).toBeUndefined();
|
|
3874
|
+
});
|
|
3802
3875
|
// ── Delete propagation (propagateDeletes) ──────────────────────────────────
|
|
3803
3876
|
//
|
|
3804
3877
|
// The bug: when a user deletes a local file, the next pull re-downloads it
|
|
@@ -5697,6 +5770,7 @@ describe("share", () => {
|
|
|
5697
5770
|
hqRoot: tmpDir,
|
|
5698
5771
|
personalMode: true,
|
|
5699
5772
|
journalSlug,
|
|
5773
|
+
scopedJournal: true,
|
|
5700
5774
|
skipUnchanged: true,
|
|
5701
5775
|
propagateDeletes: true,
|
|
5702
5776
|
propagateDeletePolicy: "owned-only",
|
|
@@ -5705,6 +5779,72 @@ describe("share", () => {
|
|
|
5705
5779
|
expect(deleteRemoteFile).toHaveBeenCalledWith(expect.anything(), key);
|
|
5706
5780
|
expect(journalAt(journalPath).files[key]).toBeUndefined();
|
|
5707
5781
|
});
|
|
5782
|
+
it("propagates every area-journal descendant of a scoped deleted directory", async () => {
|
|
5783
|
+
const journalSlug = "personal-area-scoped-directory-delete";
|
|
5784
|
+
const deleteRoot = "personal/deleted-directory";
|
|
5785
|
+
const descendants = [
|
|
5786
|
+
`${deleteRoot}/first.md`,
|
|
5787
|
+
`${deleteRoot}/nested/second.md`,
|
|
5788
|
+
];
|
|
5789
|
+
const deletedEntry = (hash) => ({
|
|
5790
|
+
hash,
|
|
5791
|
+
size: 1,
|
|
5792
|
+
syncedAt: new Date().toISOString(),
|
|
5793
|
+
direction: "up",
|
|
5794
|
+
remoteEtag: `${hash}-etag`,
|
|
5795
|
+
kind: "file",
|
|
5796
|
+
localDeleteIntent: deleteIntent(`${hash}-etag`, hash),
|
|
5797
|
+
});
|
|
5798
|
+
writeJournal(journalSlug, {
|
|
5799
|
+
version: "2",
|
|
5800
|
+
lastSync: "",
|
|
5801
|
+
pulls: [],
|
|
5802
|
+
files: {
|
|
5803
|
+
[descendants[0]]: deletedEntry("first"),
|
|
5804
|
+
[descendants[1]]: deletedEntry("second"),
|
|
5805
|
+
"other/untouched.md": deletedEntry("other"),
|
|
5806
|
+
},
|
|
5807
|
+
});
|
|
5808
|
+
const migration = new AreaLedgerMigration({
|
|
5809
|
+
rootDir: stateDir,
|
|
5810
|
+
journalSlug,
|
|
5811
|
+
resolver: new AreaResolver({
|
|
5812
|
+
format: 1,
|
|
5813
|
+
routerVersion: 1,
|
|
5814
|
+
areas: [
|
|
5815
|
+
{ id: "root:personal", prefixes: ["personal"], paths: [] },
|
|
5816
|
+
{ id: "root:other", prefixes: ["other"], paths: [] },
|
|
5817
|
+
],
|
|
5818
|
+
}),
|
|
5819
|
+
legacyStore: openJournalStateStoreForMigration(journalSlug),
|
|
5820
|
+
});
|
|
5821
|
+
expect(migration.cutOver().phase).toBe("area-authoritative");
|
|
5822
|
+
const opened = [];
|
|
5823
|
+
setAreaLedgerMigrationTestHooksForTest({ afterOpen: (bridge) => opened.push(bridge) });
|
|
5824
|
+
expect(Object.keys(readJournalScoped(journalSlug, [], [deleteRoot]).files).sort())
|
|
5825
|
+
.toEqual(descendants.slice().sort());
|
|
5826
|
+
expect(opened).toHaveLength(1);
|
|
5827
|
+
expect(opened[0].openedAreaStoresForTest()).toEqual(["@meta", "root:personal"]);
|
|
5828
|
+
closeCachedAreaJournalMigration(journalSlug);
|
|
5829
|
+
setAreaLedgerMigrationTestHooksForTest(undefined);
|
|
5830
|
+
const result = await share({
|
|
5831
|
+
paths: [],
|
|
5832
|
+
deleteScopeRoots: [deleteRoot],
|
|
5833
|
+
entityContext: makeEntityContext({ uid: "prs_personal", slug: "personal" }),
|
|
5834
|
+
hqRoot: tmpDir,
|
|
5835
|
+
personalMode: true,
|
|
5836
|
+
journalSlug,
|
|
5837
|
+
scopedJournal: true,
|
|
5838
|
+
skipUnchanged: true,
|
|
5839
|
+
propagateDeletes: true,
|
|
5840
|
+
propagateDeletePolicy: "owned-only",
|
|
5841
|
+
});
|
|
5842
|
+
expect(result.filesDeleted).toBe(descendants.length);
|
|
5843
|
+
expect(deleteRemoteFile).toHaveBeenCalledWith(expect.anything(), descendants[0]);
|
|
5844
|
+
expect(deleteRemoteFile).toHaveBeenCalledWith(expect.anything(), descendants[1]);
|
|
5845
|
+
expect(deleteRemoteFile).not.toHaveBeenCalledWith(expect.anything(), "other/untouched.md");
|
|
5846
|
+
closeCachedAreaJournalMigration(journalSlug);
|
|
5847
|
+
});
|
|
5708
5848
|
// ── Decommission prefixes ──────────────────────────────────────────────────
|
|
5709
5849
|
//
|
|
5710
5850
|
// `decommissionPrefixes` is the "company was promoted to its own team
|