You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Taking CC-Switch's config surface as the reference point, here is what these two pages can and cannot do today.
Profile: no delete exists anywhere
ProfilesPage offers create (startSetup, line 67) and edit (setEditor, line 260). There is no delete, and this is not a missing button — the capability is absent from the bottom of the stack up:
so no UseCases method, no ProfileService binding (services.go:385-395 has only ListProfiles and SaveProfile), no api.deleteProfile
A Profile created by mistake is permanent. Since Profile ID is disabled once set (ProfilesPage.tsx:178), it cannot be renamed either — a typo in an ID is unfixable through the app.
Implementing this is a four-layer change, not a frontend task. Per the write-order rules in CLAUDE.md it also has to remove the secret alongside the profile, and LoadActive needs a defined answer when the deleted Profile is the active one.
Provider: delete has no in-use guard
UseCases.DeleteProvider (internal/app/provider.go:202-212) takes writeMu and calls providers.Delete with no check of who is using it:
ProvidersPage already computes exactly the fact needed — users, the Agents whose agent.provider matches — and renders it as chips (lines 181-183, 214). It is displayed and then ignored by the confirm, which is a bare window.confirm with just the name (line 89). Deleting a Provider with three Agents bound to it succeeds silently and leaves those Agents pointing at an id that no longer resolves.
The symmetric case is handled correctly: SaveProvider reapplies to every affected Agent and reports reapplied / failures, and the page surfaces both (lines 63-77). Delete should be at least as informative.
Smaller gaps on the same theme
Deletion is gated on meta.custom (line 200), so a built-in Provider can be edited but not removed. With only two built-ins (ppio, novita) a user who wants neither is stuck with both in the list. Hiding rather than deleting would fit — the lock file is the source of truth for what ships.
The Provider list has no ordering control.byProviderCreatedAt fixes the order; there is no way to promote the one actually in use to the top.
AgentProfilePage and ProfilesPage create Profiles by different routes.AgentProfilePage.openCreate (line 180) opens an inline form and calls api.saveProfile; ProfilesPage.startSetup dispatches START_SETUP into the five-step wizard. Two paths, two mental models, one object type. Related to [P2] 「更新」按钮用前端硬编码的 npm 清单判断,已漏掉 OpenClaw,且未安装也照样显示 #61.
No duplicate/clone. The common real operation is "same Provider and model, different name," which today means retyping every field.
Suggested split
Worth separating, since they are different sizes and different risk:
Profile delete (Go through UI, four layers, needs the active-pointer decision) — the actual blocker
Provider delete in-use guard (name the bound Agents in the confirm, or refuse) — small, and prevents a broken state
Clone, ordering, built-in hiding — convenience, decide together after 1 and 2
Taking CC-Switch's config surface as the reference point, here is what these two pages can and cannot do today.
Profile: no delete exists anywhere
ProfilesPageoffers create (startSetup, line 67) and edit (setEditor, line 260). There is no delete, and this is not a missing button — the capability is absent from the bottom of the stack up:internal/profile/store.goexposesRoot,PointerPath,ProfilesPath,ProfilePath,SecretPath,List,LoadActive,LoadActiveContextinternal/profile/write.goexposesSave,WriteActive,writeStored,writeSecretDeletemethod in the packageUseCasesmethod, noProfileServicebinding (services.go:385-395has onlyListProfilesandSaveProfile), noapi.deleteProfileA Profile created by mistake is permanent. Since
Profile IDisdisabledonce set (ProfilesPage.tsx:178), it cannot be renamed either — a typo in an ID is unfixable through the app.Implementing this is a four-layer change, not a frontend task. Per the write-order rules in
CLAUDE.mdit also has to remove the secret alongside the profile, andLoadActiveneeds a defined answer when the deleted Profile is the active one.Provider: delete has no in-use guard
UseCases.DeleteProvider(internal/app/provider.go:202-212) takeswriteMuand callsproviders.Deletewith no check of who is using it:ProvidersPagealready computes exactly the fact needed —users, the Agents whoseagent.providermatches — and renders it as chips (lines 181-183, 214). It is displayed and then ignored by the confirm, which is a barewindow.confirmwith just the name (line 89). Deleting a Provider with three Agents bound to it succeeds silently and leaves those Agents pointing at an id that no longer resolves.The symmetric case is handled correctly:
SaveProviderreapplies to every affected Agent and reportsreapplied/failures, and the page surfaces both (lines 63-77). Delete should be at least as informative.Smaller gaps on the same theme
meta.custom(line 200), so a built-in Provider can be edited but not removed. With only two built-ins (ppio,novita) a user who wants neither is stuck with both in the list. Hiding rather than deleting would fit — the lock file is the source of truth for what ships.byProviderCreatedAtfixes the order; there is no way to promote the one actually in use to the top.AgentProfilePageandProfilesPagecreate Profiles by different routes.AgentProfilePage.openCreate(line 180) opens an inline form and callsapi.saveProfile;ProfilesPage.startSetupdispatchesSTART_SETUPinto the five-step wizard. Two paths, two mental models, one object type. Related to [P2] 「更新」按钮用前端硬编码的 npm 清单判断,已漏掉 OpenClaw,且未安装也照样显示 #61.Suggested split
Worth separating, since they are different sizes and different risk: