Plugin cloning via menu (#6433)

* Add plugin cloning via menu

* Split plugin commands by action

* Keep plugin enablement in action commands

* Remove unused plugin edit command

* Simplify plugin rescan arguments

* Assume Omarchy shell is running for plugin commands

* Remove plugin compatibility dispatcher

* Flatten plugin clone command

* Keep only shared plugin helpers

* Remove plugin rescan wrapper

* Keep plugin commands self-contained

* Simplify plugin clone lifecycle
This commit is contained in:
David Heinemeier Hansson
2026-07-29 21:34:47 -04:00
committed by GitHub
parent fb564e3ac1
commit f8835df644
28 changed files with 1238 additions and 1012 deletions
+12 -10
View File
@@ -183,11 +183,11 @@ assertEqual(
)
assertDeepEqual(
defaultItems.filter(item => item.parent === 'setup.plugin').map(item => item.label),
['Enable Plugin', 'Disable Plugin', 'Add Plugin', 'Remove Plugin'],
['Enable Plugin', 'Disable Plugin', 'Add Plugin', 'Clone Plugin', 'Remove Plugin'],
'menu manages plugins from Setup > Plugins'
)
assert(
['enable', 'disable', 'remove'].every(
['enable', 'disable', 'clone', 'remove'].every(
verb => defaultById[`setup.plugin.${verb}`].action === `omarchy-menu-plugin ${verb}`
),
'menu picks a plugin the way it already picks a theme or a timezone'
@@ -201,7 +201,7 @@ assert(
'menu hides Remove until a plugin the user installed exists to delete'
)
assert(
defaultById['setup.plugin.add'].action.includes('omarchy-plugin add'),
defaultById['setup.plugin.add'].action.includes('omarchy-plugin-add'),
'menu adds a plugin through the CLI, where the trust warning and clone output are visible'
)
@@ -212,23 +212,25 @@ assert(
)
assert(
/remove\).*\(\.firstParty \| not\)/.test(pluginPicker)
&& /clone\).*\.firstParty/.test(pluginPicker)
&& !/kinds|bar-widget|A_BAR_OPTION|NOT_A_BAR_OPTION|BAR_ICON/.test(pluginPicker),
'plugin picker leaves plugin-kind decisions to its data and the plugin command'
)
const pluginCli = fs.readFileSync(path.join(root, 'bin/omarchy-plugin'), 'utf8')
const pluginAdd = fs.readFileSync(path.join(root, 'bin/omarchy-plugin-add'), 'utf8')
const pluginEnable = fs.readFileSync(path.join(root, 'bin/omarchy-plugin-enable'), 'utf8')
assert(
/Now using \$id as the bar/.test(pluginCli)
&& /enabled_message "\$id"[\s\S]*?place_bar_widget/.test(pluginCli),
/Now using \$id as the bar/.test(pluginEnable)
&& /Now using \$id as the bar[\s\S]*?place_bar_widget/.test(pluginAdd),
'plugin enable reports a bar as replacing the one in use, whether enabled or freshly added'
)
assert(
/\.barWidget\.defaultSection \/\/ "center"/.test(pluginCli)
&& /gum choose[\s\S]*?--selected "\$default_section"/.test(pluginCli),
/\.barWidget\.defaultSection \/\/ "center"/.test(pluginAdd)
&& /gum choose[\s\S]*?--selected "\$default_section"/.test(pluginAdd),
'interactive plugin add selects the manifest placement or center fallback by default'
)
assert(
/omarchy-plugin "\$1" "\$id"/.test(pluginPicker),
/"omarchy-plugin-\$1" "\$id"/.test(pluginPicker),
'plugin picker delegates enable and disable without interpreting plugin kinds'
)
// Icons ride along as "<glyph>\tlabel"; the menu shows the glyph and hands
@@ -245,7 +247,7 @@ assert(
'menu select mode reads a leading icon off an option and filters on the label alone'
)
assert(
/omarchy-launch-floating-terminal-with-presentation "omarchy-plugin remove/.test(pluginPicker),
/omarchy-launch-floating-terminal-with-presentation "omarchy-plugin-remove/.test(pluginPicker),
'plugin picker removes where the confirmation and backup path are visible'
)