Add global scripts and color picker for custom scripts#305
Merged
Conversation
Introduce a "Scripts" section in app-level settings that defines `.custom` scripts available to all repos, alongside the existing per-repo scripts. Globals merge into the toolbar menu under a "Global" section and into the command palette. Toolbar exposes separate "Manage Repo Scripts…" and "Manage Global Scripts…" entries. Both editors now render via `PlainTextEditor` (moved into `SupacodeSettingsFeature`).
- ScriptMenuIdentity is now a Hashable struct hashing full ScriptDefinitions so renames and field edits invalidate the toolbar NSMenu cache. - Filter empty-command globals from the toolbar's "Global" section so half-configured entries don't pollute every repo's menu. - Collapse visibleGlobalScripts to Array(allScripts.dropFirst(...)) and let merged() own the "repo wins on ID collision" rule. - Add AppFeature.State.resolveScript(id:) and use it from runNamedScript. - decodeLossyArrayIfPresent KeyedDecodingContainer extension subsumes the ad-hoc decodeScriptsLossily helper and emits SupaLogger breadcrumbs on malformed entries / arrays. - Compare global script IDs as a Set so a pure reorder doesn't prune command-palette recency. - ColorSwatchRow: collapse a11y onto a single accessibilityElement on the Custom swatch and trim the multi-paragraph rationale comments. - AGENTS.md: enforce "decode + constructor are load-bearing for .custom; merge order is semantic, not a security guard." - Tests: palette-routed collision test + ScriptDefinition tintColor legacy-rawValue decode regression.
- TabSnapshot decodes tintColor lossily so a custom-hex value persisted on
this build doesn't nuke an entire saved layout when read by an older
build that only knows the named-color enum. AGENTS.md flags the
one-way migration.
- Lossy element decode no longer interpolates the full DecodingError —
release os.Logger uses privacy: .public, so the prior message could
leak user-defined script names and command bodies.
- Default and predefined color swatches gain the .isSelected a11y trait
so VoiceOver matches the visible selection ring on every swatch.
- RepositorySettingsFeature.removeScript shares the global-script
warning copy ("Any running instance keeps running…") and explicitly
clears state.alert on confirmation so the alert doesn't reappear when
switching settings panes or reopening the window.
- ScriptMenuIdentity uses a display-only fingerprint (id, name, icon,
tint, has-command) instead of hashing whole ScriptDefinitions; editing
a command body no longer churns the toolbar Menu identity.
- Empty-command scripts surface in the command palette as
"Configure: …" entries and route to the appropriate Settings pane
instead of being filtered out and silently dropped.
- AppFeature.State.init seeds globalScripts so allScripts isn't empty
before the first settingsChanged delegate fires.
- GlobalScriptsSettingsView scrolls the newly added section into view
so adding a global gives visible feedback when the form is taller
than the window.
- RepositoryColor predefined-case ordering aligned with the UI palette.
- AGENTS.md/GlobalSettings comment marks the .custom kind normalization
as intentionally one-way to deter "fix" PRs.
- RepositoryScriptsSettingsView wraps its Form in ScrollViewReader and
scrolls the newly-added section into view, mirroring the global pane
so adding a script gives the same feedback in both surfaces.
- AGENTS.md: tighten the toolbar visibleGlobalScripts bullet to describe
policy ("drop shadowed and empty-command globals") rather than mechanics.
marvtub
added a commit
to marvtub/supacode
that referenced
this pull request
May 11, 2026
Aligns the prompt's color picker with the post-supabitapp#305 world: drop the customColor SwiftUI Color mirror and the .selectColor action from WorktreeCreationPromptFeature, and bind directly to the shared ColorSwatchRow(color: $store.color) component instead of the now-removed RepositoryColorSwatchRow shim. Trims the matching test coverage and swaps the explicit NSColorPanel.shared.orderOut(nil) cleanup for the shared .dismissSystemColorPanelOnDisappear() modifier. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
marvtub
added a commit
to marvtub/supacode
that referenced
this pull request
May 11, 2026
Aligns the prompt's color picker with the post-supabitapp#305 world: drop the customColor SwiftUI Color mirror and the .selectColor action from WorktreeCreationPromptFeature, and bind directly to the shared ColorSwatchRow(color: $store.color) component instead of the now-removed RepositoryColorSwatchRow shim. Trims the matching test coverage and swaps the explicit NSColorPanel.shared.orderOut(nil) cleanup for the shared .dismissSystemColorPanelOnDisappear() modifier. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
marvtub
added a commit
to marvtub/supacode
that referenced
this pull request
May 12, 2026
…erenced supabitapp#305 moved `RepositoryColor` from the app target to `SupacodeSettingsShared`, so files in `supacode/Domain` that hold the type need the explicit import. Previously masked because the type was visible in the same module; the rebase on top of `main` surfaces it as a compile error. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
marvtub
added a commit
to marvtub/supacode
that referenced
this pull request
May 12, 2026
…entTests Mirrors the import already present in the other customization test files and matches the runtime fix in 78d0072. `RepositoryColor` cases like `.red` and `.blue` need the explicit import after supabitapp#305 moved the type out of the app target. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
GlobalSettings.globalScripts: [ScriptDefinition]shared across every repository, surfaced in the toolbar Script Menu, command palette, andrunScriptdeeplinks. Repo scripts win on ID collision via[ScriptDefinition].merged(repo:global:). Settings has a new "Global Scripts" pane reachable viasupacode://settings/scriptsandsupacode settings scripts.RepositoryColormoved toSupacodeSettingsShared/ModelssoScriptDefinition.tintColorcan use the same palette as repo customization, and the newColorSwatchRowis reused across both surfaces. The oldTerminalTabTintColorenum is retired.Notable invariants and hardening
kind = .customfor globals is enforced in two layers (decode + constructor); a hand-editedkind: "run"global cannot hijack the toolbar's primary "Run" slot.KeyedDecodingContainer.decodeLossyArrayIfPresent(forKey:)lossy-decodes script arrays — element failures are dropped + logged (with PII-safe messages); array-shape failures don't poison the whole settings file.TerminalLayoutSnapshot.TabSnapshot.tintColordecodes lossily so a future tint vocab change can't destroy a saved layout.ScriptMenuuses a display-only fingerprint as.id— renames invalidate the NSMenu cache without per-keystroke command rebuilds..isSelectedtrait so screen readers track the visible selection ring.Test plan
make build-appcleanmake check(format + lint) cleanAppFeatureRunScriptTests,AppFeatureDeeplinkTests,RepositoryColorTests,RepositorySettingsScriptTests,SettingsFeatureTests,TerminalLayoutSnapshotTests,CommandPaletteFeatureTests