diff --git a/memhub/apps/desktop/src/host-control-ownership.test.ts b/memhub/apps/desktop/src/host-control-ownership.test.ts index b1363a7..8074688 100644 --- a/memhub/apps/desktop/src/host-control-ownership.test.ts +++ b/memhub/apps/desktop/src/host-control-ownership.test.ts @@ -191,7 +191,12 @@ vi.mock("@one-memory/host-bridge/installer", () => ({ renderConnectionMaterial: fake.localRead, verifyRecallInstall: fake.localRead, })); -vi.mock("@one-memory/host-bridge", () => ({ +// Spread the real module instead of whitelisting it. Main imports domain +// helpers that runtime-control re-exports from host-bridge, so a partial mock +// silently hands back undefined for them and every error path that calls one +// fails with a TypeError instead of the code under test. +vi.mock("@one-memory/host-bridge", async (importOriginal) => ({ + ...(await importOriginal()), RecallBroker: class { constructor(options: unknown) { fake.brokerConstructed(options); diff --git a/memhub/apps/desktop/src/host-permissions.test.ts b/memhub/apps/desktop/src/host-permissions.test.ts index 4ea6695..6593032 100644 --- a/memhub/apps/desktop/src/host-permissions.test.ts +++ b/memhub/apps/desktop/src/host-permissions.test.ts @@ -985,7 +985,7 @@ describe.skipIf(process.platform === "win32")( ); }); - it("does not overwrite modified plugin registry ownership during uninstall", async () => { + it("reports a modified managed registry entry instead of overwriting it", async () => { const context = await fixture(); const layout = workbuddyLayout(path.join(context.root, "workbuddy")); const plugin = required(layout.plugin); @@ -1004,9 +1004,18 @@ describe.skipIf(process.platform === "win32")( config["one-memory"].installLocation = "changed-by-user"; const changed = JSON.stringify(config); await writeFile(plugin.knownMarketplacesPath, changed); + // The value at our own key changed. Overwriting it would be a guess, so + // uninstall schedules nothing, names the file in a review finding, and + // refuses when the preview is applied. The bytes stay as the host left + // them either way. + const removal = await context.permissions.previewUninstall(layout); + expect(removal.files).toEqual([]); + expect((removal.review ?? []).map((finding) => finding.path)).toContain( + plugin.knownMarketplacesPath, + ); await expect( - context.permissions.previewUninstall(layout), - ).rejects.toThrow("host_uninstall_modified_files"); + context.permissions.uninstall(layout, removal.fingerprint), + ).rejects.toThrow("host_uninstall_needs_review"); expect(await readFile(plugin.knownMarketplacesPath, "utf8")).toBe( changed, );