[TUI] add external config migration prompt when start TUI (#17891)

- add a TUI startup migration prompt for external agent config
- support migrating external configs including config, skills, AGENTS.md
and plugins
- gate the prompt behind features.external_migrate (default false)

<img width="1037" height="480" alt="Screenshot 2026-04-14 at 9 29 14 PM"
src="https://github.com/user-attachments/assets/6060849b-03cb-429a-9c13-c7bb46ad2e65"
/>
<img width="713" height="183" alt="Screenshot 2026-04-14 at 9 29 26 PM"
src="https://github.com/user-attachments/assets/d13f177e-d4c4-479c-8736-ef29636081e1"
/>

---------

Co-authored-by: Eric Traut <etraut@openai.com>
This commit is contained in:
alexsong-oai
2026-04-17 17:58:32 -07:00
committed by GitHub
co-authored by Eric Traut
parent 370bed4bf4
commit 93ff798e5b
14 changed files with 2004 additions and 15 deletions
+77
View File
@@ -43,6 +43,14 @@ pub enum ConfigEdit {
SetWindowsWslSetupAcknowledged(bool),
/// Toggle the model migration prompt acknowledgement flag.
SetNoticeHideModelMigrationPrompt(String, bool),
/// Toggle the home external config migration prompt acknowledgement flag.
SetNoticeHideExternalConfigMigrationPromptHome(bool),
/// Record when the home external config migration prompt was last shown.
SetNoticeExternalConfigMigrationPromptHomeLastPromptedAt(i64),
/// Toggle the project external config migration prompt acknowledgement flag.
SetNoticeHideExternalConfigMigrationPromptProject(String, bool),
/// Record when the project external config migration prompt was last shown.
SetNoticeExternalConfigMigrationPromptProjectLastPromptedAt(String, i64),
/// Record that a migration prompt was shown for an old->new model mapping.
RecordModelMigrationSeen { from: String, to: String },
/// Replace the entire `[mcp_servers]` table.
@@ -421,6 +429,53 @@ impl ConfigDocument {
value(*acknowledged),
))
}
ConfigEdit::SetNoticeHideExternalConfigMigrationPromptHome(acknowledged) => Ok(self
.write_value(
Scope::Global,
&[
NOTICE_TABLE_KEY,
"external_config_migration_prompts",
"home",
],
value(*acknowledged),
)),
ConfigEdit::SetNoticeExternalConfigMigrationPromptHomeLastPromptedAt(timestamp) => {
Ok(self.write_value(
Scope::Global,
&[
NOTICE_TABLE_KEY,
"external_config_migration_prompts",
"home_last_prompted_at",
],
value(*timestamp),
))
}
ConfigEdit::SetNoticeHideExternalConfigMigrationPromptProject(
project,
acknowledged,
) => Ok(self.write_value(
Scope::Global,
&[
NOTICE_TABLE_KEY,
"external_config_migration_prompts",
"projects",
project.as_str(),
],
value(*acknowledged),
)),
ConfigEdit::SetNoticeExternalConfigMigrationPromptProjectLastPromptedAt(
project,
timestamp,
) => Ok(self.write_value(
Scope::Global,
&[
NOTICE_TABLE_KEY,
"external_config_migration_prompts",
"project_last_prompted_at",
project.as_str(),
],
value(*timestamp),
)),
ConfigEdit::RecordModelMigrationSeen { from, to } => Ok(self.write_value(
Scope::Global,
&[NOTICE_TABLE_KEY, "model_migrations", from.as_str()],
@@ -919,6 +974,28 @@ impl ConfigEditsBuilder {
self
}
pub fn set_hide_external_config_migration_prompt_home(mut self, acknowledged: bool) -> Self {
self.edits
.push(ConfigEdit::SetNoticeHideExternalConfigMigrationPromptHome(
acknowledged,
));
self
}
pub fn set_hide_external_config_migration_prompt_project(
mut self,
project: &str,
acknowledged: bool,
) -> Self {
self.edits.push(
ConfigEdit::SetNoticeHideExternalConfigMigrationPromptProject(
project.to_string(),
acknowledged,
),
);
self
}
pub fn record_model_migration_seen(mut self, from: &str, to: &str) -> Self {
self.edits.push(ConfigEdit::RecordModelMigrationSeen {
from: from.to_string(),