merge: resolve v1.22.2 conflicts with custom

Per Q4 resolution (documented on kanban t_83741c53):
- .github/workflows/*: KEEP custom deletion (fork uses Gitea Actions under .gitea/workflows)
- ChatInput.tsx: KEEP custom forge picker states + provider-aware linkedPr
- WorkStatusContextSection.tsx: combine imports (WorkStatusPill + useConfigStore)
- WorkStatusPrimaryGroup.tsx: upstream nested-git/bootstrap-gate base + custom GitLab/Gitea forge rows
- NewWorktreeDialog.tsx: combine dialogs; keep custom MR/PR branch resolution
- SettingsView.tsx: custom deps minus undefined openThirdPartyProviderSetup
- search.ts + search.test.ts: KEEP upstream (enter-to-send, large-text-paste, first-party integrations)
- tr.ts: drop 4 auto-merge duplicate gitView.empty.* keys
This commit is contained in:
2026-09-06 10:55:54 +00:00
220 changed files with 45375 additions and 3531 deletions
@@ -238,6 +238,42 @@ const stripDerived = (source: Record<string, unknown>): Record<string, unknown>
return next;
};
const GIT_PROVIDER_KEYS = ['github', 'gitlab', 'gitea'];
// Light shape check for the `gitProviders` settings section coming from the
// webview: reject non-objects outright, coerce detectUrls to a string array and
// apiBaseUrl to a trimmed string, and drop empty provider entries. Keeps a
// malformed payload from landing on disk (the shared settings file).
const sanitizeGitProviders = (input: unknown): Record<string, unknown> | undefined => {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
return undefined;
}
const source = input as Record<string, unknown>;
const result: Record<string, unknown> = {};
for (const key of GIT_PROVIDER_KEYS) {
const entry = source[key];
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
continue;
}
const record = entry as Record<string, unknown>;
const apiBaseUrl = typeof record.apiBaseUrl === 'string' ? record.apiBaseUrl.trim() : '';
const detectUrls = Array.isArray(record.detectUrls)
? record.detectUrls.filter((value): value is string => typeof value === 'string')
: [];
const provider: Record<string, unknown> = {};
if (apiBaseUrl) {
provider.apiBaseUrl = apiBaseUrl;
}
if (detectUrls.length > 0) {
provider.detectUrls = detectUrls;
}
if (Object.keys(provider).length > 0) {
result[key] = provider;
}
}
return Object.keys(result).length > 0 ? result : undefined;
};
let eagerMigrationAttempted = false;
// Read the merged persisted settings: shared file is canonical (synced with
@@ -330,6 +366,15 @@ export const persistSettings = async (changes: Record<string, unknown>, ctx?: Br
}
}
if ('gitProviders' in restChanges) {
const gitProviders = sanitizeGitProviders(restChanges.gitProviders);
if (gitProviders) {
restChanges.gitProviders = gitProviders;
} else {
delete restChanges.gitProviders;
}
}
if (typeof restChanges.opencodeBinary === 'string') {
restChanges.opencodeBinary = restChanges.opencodeBinary.trim();
}