From 23d6fa4ff2a7e42f3f233e22eb4fefd973a9046f Mon Sep 17 00:00:00 2001 From: sy Date: Tue, 25 Aug 2026 02:03:54 -0700 Subject: [PATCH 1/2] fix(frontend): avoid Windows title-bar control overlap --- App/frontend/desktop/src/styles.css | 8 ++++++++ .../desktop/src/theme/tests/style-alignment.test.ts | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/App/frontend/desktop/src/styles.css b/App/frontend/desktop/src/styles.css index eb8e7b431..57def6074 100644 --- a/App/frontend/desktop/src/styles.css +++ b/App/frontend/desktop/src/styles.css @@ -3894,6 +3894,10 @@ code { margin-bottom: 20px; } +body.memmy-platform-windows .memory-panel__header { + padding-top: var(--codex-toolbar-height); +} + .memory-panel__header--single-line { align-items: flex-start; flex-wrap: wrap; @@ -5055,6 +5059,10 @@ code { -webkit-app-region: no-drag; } +body.memmy-platform-windows .memory-drawer { + padding-top: var(--codex-toolbar-height); +} + .memory-drawer, .memory-drawer * { -webkit-app-region: no-drag; diff --git a/App/frontend/desktop/src/theme/tests/style-alignment.test.ts b/App/frontend/desktop/src/theme/tests/style-alignment.test.ts index d4d748fca..3e074770b 100644 --- a/App/frontend/desktop/src/theme/tests/style-alignment.test.ts +++ b/App/frontend/desktop/src/theme/tests/style-alignment.test.ts @@ -310,6 +310,18 @@ describe("prototype style alignment", () => { expect(globalCss).not.toContain(".memory-drawer__copy-id"); }); + it("keeps the Windows memory refresh action below the native title-bar overlay", () => { + const windowsMemoryHeaderRule = globalCss.match(/body\.memmy-platform-windows \.memory-panel__header\s*\{[^}]*\}/)?.[0] ?? ""; + + expect(windowsMemoryHeaderRule).toContain("padding-top: var(--codex-toolbar-height);"); + }); + + it("keeps the Windows memory drawer close action below the native title-bar overlay", () => { + const windowsMemoryDrawerRule = globalCss.match(/body\.memmy-platform-windows \.memory-drawer\s*\{[^}]*\}/)?.[0] ?? ""; + + expect(windowsMemoryDrawerRule).toContain("padding-top: var(--codex-toolbar-height);"); + }); + it("copies mascot assets into the App source tree instead of referencing the prototype folder", () => { const assetNames = [ "memmy-rice.png", From 7165f39156070751331fbb061a7767b4f13d67c1 Mon Sep 17 00:00:00 2001 From: sy Date: Tue, 25 Aug 2026 02:25:59 -0700 Subject: [PATCH 2/2] fix(frontend): clear stale model assignments on deletion --- .../desktop/src/state/model-workspace.ts | 3 + .../src/state/tests/model-workspace.test.ts | 58 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/App/frontend/desktop/src/state/model-workspace.ts b/App/frontend/desktop/src/state/model-workspace.ts index 822100b84..fb17f9d59 100644 --- a/App/frontend/desktop/src/state/model-workspace.ts +++ b/App/frontend/desktop/src/state/model-workspace.ts @@ -474,12 +474,15 @@ export function upsertModelConnection( const previousPresetIds = existingConnection ? existingConnection.modelEntries.map((entry) => entry.presetId) : []; + const removedPresetIds = previousPresetIds.filter((id) => !nextPresetIds.includes(id)); const assignment = next.modelAssignments[mode]; assignment.agent.candidates = replaceIds(assignment.agent.candidates, previousPresetIds, nextAgentPresetIds); if (!assignment.agent.candidates.length) assignment.agent.candidates = [...nextAgentPresetIds]; if (!assignment.agent.default || previousPresetIds.includes(assignment.agent.default)) { assignment.agent.default = nextPresetIds.find((id) => presetHasCapability(next, id, "agent")) ?? assignment.agent.default; } + clearAssignmentReferences(next.modelAssignments.byok, removedPresetIds); + clearAssignmentReferences(next.modelAssignments.account, removedPresetIds); refreshEffectiveCandidates(next); return { workspace: createModelWorkspace(next), error: null }; } diff --git a/App/frontend/desktop/src/state/tests/model-workspace.test.ts b/App/frontend/desktop/src/state/tests/model-workspace.test.ts index b9a965f44..b50b52440 100644 --- a/App/frontend/desktop/src/state/tests/model-workspace.test.ts +++ b/App/frontend/desktop/src/state/tests/model-workspace.test.ts @@ -405,6 +405,64 @@ describe("canonical model workspace adapter", () => { expect(saved.providers[0]!.models.map((model) => model.model)).not.toContain("embedding-delete"); }); + it("真实 Backend catalog:编辑连接删除已分配模型时清理双空间引用", async () => { + const file = catalogFixture(); + const empty = await readModelConfigCatalog(file); + const created = await writeModelConfigCatalog(file, { + configRevision: empty.configRevision, + providers: [{ + provider: "openai", + endpoints: [{ + endpointId: "embedding", + apiBase: "https://api.openai.com/v1", + protocol: "openai-embeddings", + apiKey: "sk-delete-model" + }], + models: [ + { endpointId: "embedding", model: "embedding-delete", source: "byok", capabilities: ["embedding"] }, + { endpointId: "embedding", model: "embedding-keep", source: "byok", capabilities: ["embedding"] } + ] + }], + modelAssignments: structuredClone(emptyAssignments) + }); + const removedPreset = created.providers[0]!.models.find((model) => model.model === "embedding-delete")!; + const assignedInput = modelConfigInput(createModelWorkspace(created)); + assignedInput.modelAssignments.byok.embedding = removedPreset.presetId; + assignedInput.modelAssignments.account.embedding = removedPreset.presetId; + const base = await writeModelConfigCatalog(file, assignedInput); + const workspace = createModelWorkspace(base); + const connection = workspace.spaces.byok.connections.find((item) => item.endpointId === "embedding")!; + const keptPreset = connection.modelEntries.find((model) => model.model === "embedding-keep")!; + + const edited = upsertModelConnection(workspace, "byok", { + id: connection.id, + provider: connection.provider, + endpoint: connection.endpoint, + protocol: connection.protocol, + apiKeyMasked: connection.apiKeyMasked, + models: [keptPreset.model], + modelEntries: [{ + presetId: keptPreset.presetId, + model: keptPreset.model, + capability: keptPreset.capability + }] + }); + + expect(edited.error).toBeNull(); + expect(edited.workspace.catalog.modelAssignments.byok.embedding).toBeNull(); + expect(edited.workspace.catalog.modelAssignments.account.embedding).toBeNull(); + + await expect(persistModelCatalogMutation(modelConfigInput(edited.workspace), { + read: () => readModelConfigCatalog(file), + write: (input) => writeModelConfigCatalog(file, input) + }, base)).resolves.toMatchObject({ + modelAssignments: { + byok: { embedding: null }, + account: { embedding: null } + } + }); + }); + it("真实 Backend catalog:从账号空间删除共享 DashScope 配置并清理双空间引用", async () => { const file = catalogFixture(); const empty = await readModelConfigCatalog(file);