Customizations: consolidate the two independent "disabled" stores
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
### Problem
Whether a chat customization is "disabled" is tracked in **two independent, unsynchronised stores**:
| # | Store | Storage key | Scope / target | Serialization | Written by |
|---|---|---|---|---|---|
| 1 | `IPromptsService.get/setDisabledPromptFiles(type)` (`promptsServiceImpl.ts`) | `chat.disabledPromptFiles.` | `PROFILE` / `USER` | `uri.toJSON()` + `URI.revive()` | the **Disable/Enable** actions in `aiCustomizationManagement.contribution.ts` |
| 2 | `AgentCustomizationSyncProvider` (`ICustomizationSyncProvider`) | `customizationSync.disabled.` | `PROFILE` / `MACHINE` | `uri.toString()` | only `pluginListWidget.ts` (plugins) |
Nothing keeps them in agreement, and they differ in storage target (`USER` vs `MACHINE`, so one syncs across machines and the other does not) and in URI serialization.
Consumers pick one essentially at random:
- `enumerateLocalCustomizationsForHarness` read store 2 only.
- `PureItemProviderItemSource` read neither.
- `ItemProviderItemSource` reads store 1.
- The older sessions tree view (`aiCustomizationTreeViewViews.ts`) reads store 1.
This is the direct cause of #329751, where the Agents window wrote to store 1 and every relevant consumer read store 2. It produced a particularly confusing symptom: the older sessions tree view *did* reflect the disabled state, so the same skill appeared disabled in one surface and enabled in another, while the agent host kept receiving it either way.
### Why this is worth fixing structurally
The immediate fix for #329751 makes the agent-host wire consult *both* stores (`syncProvider.isDisabled(uri) || userDisabled.has(uri)`). That resolves the user-visible bug but entrenches the split: every future consumer now has to remember to OR the two together, and every future writer has to pick the right one. The bug is likely to recur in the next surface that ships.
### Suggested direction
Consolidate on a single source of truth for "is this customization disabled", most naturally on `IPromptsService`, with the sync provider's per-harness store either folded into it or kept strictly as a harness-scoped overlay with an explicit, documented precedence rule. Whichever way it goes, there should be exactly one function that answers the question, and the storage target and URI serialization should be consistent.
The two stores and the requirement to consult both are documented for now in `src/vs/sessions/AI_CUSTOMIZATIONS.md` under *Built-in Skills → Enabling and Disabling Built-in Skills*.
Found while investigating #329751.
Contributor guide
Assessment
This issue has not been assessed yet.