Add multiple user-defined scripts per repository#246
Merged
Conversation
Introduce the foundational data model for multiple running scripts: - ScriptKind enum with predefined types (run, debug, test, deploy, custom), each carrying default icon, color, and name. - ScriptDefinition struct with id, kind, name, systemImage, tintColor, and command fields. - Move TerminalTabTintColor to SupacodeSettingsShared and extend with blue, purple, yellow, and teal cases for new script types. - Refactor BlockingScriptKind: replace .run with .script(ScriptDefinition) to support multiple concurrent user-defined scripts while keeping .archive and .delete as lifecycle-bound cases. - Add scripts and selectedScriptID fields to RepositorySettings with backward-compatible migration from the legacy runScript field. - Update all downstream switch sites, terminal state tracking, and tests.
Register testScript (Cmd+Shift+U), debugScript (Cmd+Shift+Y), and deployScript (Cmd+Shift+D) in AppShortcutID with stable keys, display names, and Ghostty unbind support. Add corresponding menu items in WorktreeCommands and wire focused value actions through WorktreeDetailView. Actions are currently nil placeholders — they will be connected to AppFeature in a later commit.
Split repository settings into General and Scripts sub-sections via expandable DisclosureGroup in the sidebar. The Scripts section shows a list-based editor where each row has a ScriptKind picker, name field, and monospaced command field with add/remove/reorder support. Remove the old single "Run Script" ScriptSection from the General settings — lifecycle scripts (setup, archive, delete) stay as-is. Add reducer tests for addScript, removeScripts, and moveScripts actions covering edge cases (remove middle, move to end, move to beginning).
Replace RunScriptToolbarButton with ScriptSplitButton: primary button runs the selected script, chevron dropdown lists all scripts with per-type icons and run/stop per-script. Cmd+. only stops .run kind. Rewrite AppFeature script state: replace selectedRunScript/runScriptDraft with scripts array and selectedScriptID. Wire testScript/debugScript/ deployScript actions to run the first matching script kind. Add command palette entries: "Run: <name>" and "Stop: <name>" generated dynamically from repository scripts. Selected script shows Cmd+R badge. Replace runScriptWorktreeIDs with runningScriptsByWorktreeID dictionary for per-definition-ID tracking. Remove RunScriptPromptView — scripts are now configured via Settings.
Replace the single-color boolean PingDot with MultiColorPingDot that cycles through tint colors of all running script types per worktree. Uses TimelineView for smooth color transitions and falls back to a static dot when accessibilityReduceMotion is enabled. Add scriptTintColorByID cache to RepositoriesFeature.State for efficient color lookup without passing full ScriptDefinition arrays through the view hierarchy. Cache is maintained alongside runningScriptsByWorktreeID on script start, completion, and pruning.
- Add custom encode(to:) deriving runScript from first .run script for backward compatibility with older app versions. - Guard against running the same script definition twice concurrently. - Navigate to repositoryScripts settings (not General) when no scripts are configured and user presses Cmd+R. - Use try? for scripts decode so unknown ScriptKind values from future versions fall back gracefully instead of crashing. - Remove selectedScriptID entirely — primary toolbar button always runs the first .run-kind script, matching the "Open In" pattern. - Enforce at most one script per predefined kind in settings (only .custom allows duplicates). - Add Codable migration tests: legacy decode, dual-key decode, encode round-trip, and unknown-kind resilience.
Add .lint and .format cases to ScriptKind with dedicated SF Symbols and colors. Add displayName computed property to ScriptDefinition: predefined types use their kind name, custom types use user name. Lock script kind at creation: the + button opens a Menu showing only unused predefined kinds plus always-available custom. Kind picker replaced with static icon in script rows. Uniqueness enforced at insertion in addScript(ScriptKind). Move TerminalTabTintColor.color to shared module so SupacodeSettingsFeature can access it. Add lintScript/formatScript keyboard shortcuts (Cmd+Shift+L/F), menu items, and focused value wiring.
Remove debug script kind. Add resolvedSystemImage/resolvedTintColor to ScriptDefinition so non-custom scripts always derive visuals from ScriptKind defaults rather than persisted values. Add Image.tintedSymbol helper for colored SF Symbols in macOS menus (auto-resolves .fill variants via AppKit palette colors). Use tinted icons in toolbar script dropdown, plain icons in menu bar. Hide toolbar dropdown chevron when only a .run script is configured. Fix DisclosureGroup: auto-expands on selection, allows manual collapse. Navigate to Scripts settings tab (not General) from toolbar and Cmd+R. Move lifecycle scripts to Scripts tab. Remove non-run/stop keyboard shortcuts entirely (deferred to future iteration). Extend Makefile and swiftlint to cover SupacodeSettingsShared/SupacodeSettingsFeature.
- Remove `scriptTintColorByID` side-cache from RepositoriesFeature; resolve colors from current script definitions via environment. - Use `displayName` in BlockingScriptKind.tabTitle and settings header. - Encode `runScript` as empty string when no .run scripts exist. - Distinguish absent vs corrupted `scripts` key in lossy decoder. - Document `runScript` as legacy backward-compat field. - Extract duplicated `shortcutDisplay` into shared free function. - Add test for encode fallback with no .run-kind script. - Update RepositorySettingsKeyTests to use setupScript for round-trips.
- Fix sidebar indicator disappearing for scripts running in non-selected repositories by falling back to .green when script ID lookup fails - Refactor .binding case to reuse persistAndNotify, removing duplication - Extract scriptButton helper in ScriptSplitButton to DRY three branches - Extract LifecycleScriptSection in RepositoryScriptsSettingsView - Make runScript property private(set) to prevent accidental direct mutation - Clarify stopRunScripts intent with expanded doc comments
- Pre-compute scriptsByID dictionary once in environment instead of rebuilding per sidebar row in runningScriptColors - Add test verifying duplicate runNamedScript is silently rejected - Add trailing dots to help text strings for convention consistency
Show an alert before removing a user-defined script in repository settings. Also extract SettingsView subviews to fix type-checker timeout caused by the new @presents alert state.
- Extract duplicate isExpanded Binding to local let in SettingsView - Update toolbar placeholder to match live ScriptMenu (play instead of play.fill, Label instead of HStack) - Guard against empty shortcut display in resolveShortcutDisplay - Use fallback label in ScriptMenu when shortcut resolves to empty - Use stroke-only stop icon consistently (stop instead of stop.fill) - Make Divider conditional on non-empty scripts in ScriptMenu dropdown - Fix doc comments for ScriptMenu and primaryScript
Whoaa512
added a commit
to Whoaa512/supacode
that referenced
this pull request
Apr 16, 2026
* fix/unfocused-split-opacity: (24 commits) add xcbeautify to mise.toml so local builds work without separate install install dev build as supacode-dev.app to coexist with homebrew install ignore legacy Ghostty build outputs work around Xcode 26.4 local builds Respect unfocused-split-opacity from Ghostty config Add multiple user-defined scripts per repository (supabitapp#246) Respect ghostty split-preserve-zoom config when cycling splits (supabitapp#241) Improve open worktree UX and rename openFinder to openWorktree (supabitapp#247) Add RubyMine editor support (supabitapp#248) fix(ci): skip tuist auth on fork pull requests stuff Align trailing comma tooling cache Split dependency inspection CI Switch Tuist CI auth to OIDC simplify build output formatting simplify app tuist dependencies simplify tuist package linkage restore required tuist package overrides remove package framework search paths ... # Conflicts: # supacode/Features/Repositories/Views/WorktreeRow.swift # supacode/Features/Repositories/Views/WorktreeRowsView.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
runScriptfield with an orderedscripts: [ScriptDefinition]array, allowing users to configure multiple on-demand scripts (run, test, deploy, lint, format, custom) per repository..runscript, chevron dropdown lists all scripts with run/stop actions.runScriptJSON auto-migrates on decode;runScriptis derived on encode so older clients still work. Lossy decoding gracefully drops unknown futureScriptKindvalues.Closes #145
Closes #156
Test plan
runScriptconfigured auto-migrate to a.run-kindScriptDefinition.run-kind scripts; individual scripts stoppable via dropdown/paletteScriptKindvalues in JSON drop only that entry, not the entire arrayrunScriptfor backward compatibility