@indigoai-us/hq-cloud 6.13.2 → 6.13.3

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.
@@ -2645,6 +2645,94 @@ describe("sync", () => {
2645
2645
  // Local directory still intact.
2646
2646
  expect(fs.existsSync(path.join(localDir, "inside.md"))).toBe(true);
2647
2647
  });
2648
+ it("stale personal-overlay marker vs release-shipped core dir: skips cleanly, no 'rm -rf' advice (feedback_ce9aeede)", async () => {
2649
+ // Reporter feedback_ce9aeede: a stale personal-overlay symlink marker in
2650
+ // the vault at core/knowledge/public/agent-browser collided with the REAL,
2651
+ // release-shipped core directory of the same name (the overlay mirror once
2652
+ // symlinked it into core/, pushed the marker, then a release shipped a real
2653
+ // dir there). Pre-fix, the pull planner hit the generic dir-vs-object
2654
+ // collision branch and emitted, on EVERY sync, a "manual reconciliation
2655
+ // required (rm -rf the local directory to pull)" warning — advice that here
2656
+ // would DESTROY release-shipped core content to pull an inert marker. The
2657
+ // reporter had to hand-delete the vault object. Fix: recognize the
2658
+ // overlay-mirror core key, keep the local directory, and skip quietly.
2659
+ const markerKey = "core/knowledge/public/agent-browser";
2660
+ const localDir = path.join(tmpDir, "core", "knowledge", "public", "agent-browser");
2661
+ fs.mkdirSync(localDir, { recursive: true });
2662
+ fs.writeFileSync(path.join(localDir, "INDEX.md"), "release-shipped core content");
2663
+ vi.mocked(s3Module.listRemoteFiles).mockResolvedValueOnce([
2664
+ { key: markerKey, size: 40, lastModified: new Date(), etag: '"stale-marker"' },
2665
+ ]);
2666
+ const errSpy = vi.spyOn(console, "error").mockImplementation(() => { });
2667
+ let crashed = false;
2668
+ let result;
2669
+ try {
2670
+ result = await sync({
2671
+ company: "acme",
2672
+ vaultConfig: mockConfig,
2673
+ hqRoot: tmpDir,
2674
+ // personalMode → companyRoot === hqRoot, so a `core/...` key resolves
2675
+ // under the HQ root exactly as the reporter's personal-vault pull did.
2676
+ personalMode: true,
2677
+ });
2678
+ }
2679
+ catch {
2680
+ crashed = true;
2681
+ }
2682
+ const errOutput = errSpy.mock.calls.map((c) => c.join(" ")).join("\n");
2683
+ errSpy.mockRestore();
2684
+ expect(crashed).toBe(false);
2685
+ expect(result).toBeDefined();
2686
+ // Marker ignored, nothing downloaded, release-shipped dir intact.
2687
+ expect(result.filesDownloaded).toBe(0);
2688
+ expect(result.filesSkipped).toBe(1);
2689
+ expect(fs.readFileSync(path.join(localDir, "INDEX.md"), "utf-8")).toBe("release-shipped core content");
2690
+ // The dangerous, recurring reconciliation advice is GONE...
2691
+ expect(errOutput).not.toContain("rm -rf");
2692
+ expect(errOutput).not.toContain("manual");
2693
+ // ...replaced by a calm, no-action-needed note naming the stale marker.
2694
+ expect(errOutput).toContain("stale personal-overlay marker");
2695
+ expect(errOutput).toContain(markerKey);
2696
+ });
2697
+ it("dir-vs-object collision OUTSIDE the overlay-mirror core namespace still warns to reconcile (no over-broadening)", async () => {
2698
+ // Boundary guard for the feedback_ce9aeede fix: the quiet skip is scoped to
2699
+ // core/{knowledge,policies,workers,settings}/ overlay-mirror keys ONLY. A
2700
+ // dir-vs-object collision at any OTHER key (here `core/docs/...`, a core
2701
+ // subtree that is NOT an overlay-mirror type) is a genuine structural
2702
+ // collision the operator must resolve, so the original warning path — and
2703
+ // its skip-local-only classification — must remain intact.
2704
+ const key = "core/docs/agent-browser";
2705
+ const localDir = path.join(tmpDir, "core", "docs", "agent-browser");
2706
+ fs.mkdirSync(localDir, { recursive: true });
2707
+ fs.writeFileSync(path.join(localDir, "inside.md"), "local content");
2708
+ vi.mocked(s3Module.listRemoteFiles).mockResolvedValueOnce([
2709
+ { key, size: 40, lastModified: new Date(), etag: '"obj"' },
2710
+ ]);
2711
+ const errSpy = vi.spyOn(console, "error").mockImplementation(() => { });
2712
+ let crashed = false;
2713
+ let result;
2714
+ try {
2715
+ result = await sync({
2716
+ company: "acme",
2717
+ vaultConfig: mockConfig,
2718
+ hqRoot: tmpDir,
2719
+ personalMode: true,
2720
+ });
2721
+ }
2722
+ catch {
2723
+ crashed = true;
2724
+ }
2725
+ const errOutput = errSpy.mock.calls.map((c) => c.join(" ")).join("\n");
2726
+ errSpy.mockRestore();
2727
+ expect(crashed).toBe(false);
2728
+ expect(result.filesDownloaded).toBe(0);
2729
+ expect(result.filesSkipped).toBe(1);
2730
+ expect(fs.existsSync(path.join(localDir, "inside.md"))).toBe(true);
2731
+ // Generic collision path preserved: reconciliation warning still emitted,
2732
+ // NOT the overlay-marker note.
2733
+ expect(errOutput).toContain("manual");
2734
+ expect(errOutput).not.toContain("stale personal-overlay marker");
2735
+ });
2648
2736
  it("pulls a remote symlink record under an .hqinclude dir-only allowlist pattern", async () => {
2649
2737
  // Codex round-7 P1 follow-up: pre-fix, computePullPlan called
2650
2738
  // shouldSync(localPath) with the default isDir=false. LIST gives