Compare commits

..

4 Commits

Author SHA1 Message Date
Alan Wizemann 2b25a9da71 chore: Bump version to 2.2.0 2026-04-23 18:25:18 +02:00
Alan Wizemann 5fb9620631 Merge branch 'project-sharing': v2.2.0 — templates + configuration + catalog
Brings in 22 commits delivering the full v2.2.0 scope:

- Project Templates: .scarftemplate bundle format (install, uninstall,
  export, URL router) + install preview sheet + cross-agent AGENTS.md
- Template Configuration (schemaVersion 2): typed schema with 7 field
  types, Keychain-backed secrets, Configure step in install flow,
  post-install Configuration editor, model recommendations
- Template Catalog: gh-pages site generated from templates/<author>/<name>/,
  stdlib-only Python validator mirroring Swift invariants, PR CI gate,
  install-URL hosting from raw main
- Example template: awizemann/site-status-checker (config + cron + Site
  tab webview updates)
- Site tab: webview widget in any dashboard exposes a second tab
- UX: Remove from List vs. Uninstall Template clarification, preserved-
  files banner, Run Now no longer blocks on long agent runs, markdown
  in install sheet, install-time {{PROJECT_DIR}} token substitution

Release notes at releases/v2.2.0/RELEASE_NOTES.md (94 lines).
Wiki page at https://github.com/awizemann/scarf/wiki/Project-Templates.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 18:20:07 +02:00
Alan Wizemann 97e9beea5f refactor(settings): remove unused providers list
The hardcoded `providers` array in SettingsViewModel was never referenced — no view reads `viewModel.providers`; the Model picker uses the models.dev catalog via `ModelCatalogService.loadProviders()` and Provider is shown as a `ReadOnlyRow` in the General tab. Leaving the dead list around makes issues like #33 look plausible (users reasonably guess a stale enum is normalising `openai-codex` → `openai` on save, which the code does not actually do).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 02:37:50 +02:00
Alan Wizemann 7a99547b22 fix: address code-review findings from Apr 22 commits
Three follow-ups from reviewing 1989fee (sidebar-width persist) and
4163595 (default server on launch):

- `SplitViewAutosaveFinder` hardcoded `"ScarfMainSidebar"` for every
  window. Since Scarf's `WindowGroup` spawns one window per `ServerID`,
  all windows shared the same `NSSplitView.autosaveName` — AppKit
  documents that name as required-unique, and in practice per-window
  widths collapsed onto a single UserDefaults key. Thread the window's
  `ServerContext` in through `@Environment(\.serverContext)` (already
  wired at `WindowGroup` construction) and suffix the name with the
  server UUID.
- `setDefaultServer` fired `onEntriesChanged`, whose sole consumer is
  `ServerLiveStatusRegistry.rebuild()` for menu-bar fanout. Flipping a
  default flag doesn't change the set of servers; the callback was
  semantic noise. Drop the call — SwiftUI views still redraw on the
  flag flip via `@Observable`'s tracking of `entries`.
- The filled-yellow star in `ManageServersView` had a no-op action
  inside `if !isDefault { ... }` but still animated its pressed state
  on click. Replace the conditional with `.disabled(isDefault)` so the
  row is visually inert when it already is the default.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 02:37:50 +02:00
5 changed files with 24 additions and 19 deletions
+12 -12
View File
@@ -436,7 +436,7 @@
CODE_SIGN_ENTITLEMENTS = scarf/scarf.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 22;
CURRENT_PROJECT_VERSION = 23;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 3Q6X2L86C4;
ENABLE_APP_SANDBOX = NO;
@@ -449,7 +449,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 2.1.0;
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.scarf.app;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
@@ -471,7 +471,7 @@
CODE_SIGN_ENTITLEMENTS = scarf/scarf.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 22;
CURRENT_PROJECT_VERSION = 23;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 3Q6X2L86C4;
ENABLE_APP_SANDBOX = NO;
@@ -484,7 +484,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 2.1.0;
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.scarf.app;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
@@ -502,12 +502,12 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 22;
CURRENT_PROJECT_VERSION = 23;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 3Q6X2L86C4;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 26.2;
MARKETING_VERSION = 2.1.0;
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.scarfTests;
PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = NO;
@@ -524,12 +524,12 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 22;
CURRENT_PROJECT_VERSION = 23;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 3Q6X2L86C4;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 26.2;
MARKETING_VERSION = 2.1.0;
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.scarfTests;
PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = NO;
@@ -545,11 +545,11 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 22;
CURRENT_PROJECT_VERSION = 23;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 3Q6X2L86C4;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 2.1.0;
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.scarfUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = NO;
@@ -565,11 +565,11 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 22;
CURRENT_PROJECT_VERSION = 23;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 3Q6X2L86C4;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 2.1.0;
MARKETING_VERSION = 2.2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.scarfUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = NO;
@@ -82,6 +82,11 @@ final class ServerRegistry {
/// Flip the default server to `id`. Passing `ServerContext.local.id`
/// clears the flag on every remote entry, making Local the implicit
/// default. Passing an unknown ID is a no-op. Persisted on return.
///
/// Intentionally doesn't fire `onEntriesChanged` that hook means "the
/// set of servers changed" and drives the menu-bar fanout rebuild. A
/// default-flag flip doesn't change the set; SwiftUI views reading
/// `defaultServerID` redraw via `@Observable`'s tracking of `entries`.
func setDefaultServer(_ id: ServerID) {
var changed = false
for idx in entries.indices {
@@ -93,7 +98,6 @@ final class ServerRegistry {
}
if changed {
save()
onEntriesChanged?()
}
}
@@ -143,19 +143,20 @@ struct ManageServersView: View {
}
/// A star button that marks the open-on-launch default. Filled + yellow
/// on the current default row (and non-interactive clicking it is a
/// no-op since the flag is already set); outline + secondary elsewhere,
/// clicking promotes that row to default.
/// on the current default row (disabled, since clicking would be a
/// no-op); outline + secondary elsewhere, clicking promotes that row
/// to default.
@ViewBuilder
private func defaultStar(for id: ServerID, currentDefault: ServerID) -> some View {
let isDefault = id == currentDefault
Button {
if !isDefault { registry.setDefaultServer(id) }
registry.setDefaultServer(id)
} label: {
Image(systemName: isDefault ? "star.fill" : "star")
.foregroundStyle(isDefault ? .yellow : .secondary)
}
.buttonStyle(.borderless)
.disabled(isDefault)
.help(isDefault ? "Opens on launch" : "Set as default — open this server when Scarf launches.")
}
@@ -20,7 +20,6 @@ final class SettingsViewModel {
var hermesRunning = false
var rawConfigYAML = ""
var personalities: [String] = []
var providers = ["anthropic", "openrouter", "nous", "openai-codex", "google-ai-studio", "xai", "ollama-cloud", "zai", "kimi-coding", "minimax"]
var terminalBackends = ["local", "docker", "singularity", "modal", "daytona", "ssh"]
var browserBackends = ["browseruse", "firecrawl", "local"]
var ttsProviders = ["edge", "elevenlabs", "openai", "minimax", "mistral", "neutts"]
+2 -1
View File
@@ -2,6 +2,7 @@ import SwiftUI
struct SidebarView: View {
@Environment(AppCoordinator.self) private var coordinator
@Environment(\.serverContext) private var serverContext
var body: some View {
@Bindable var coordinator = coordinator
@@ -59,6 +60,6 @@ struct SidebarView: View {
}
.listStyle(.sidebar)
.navigationTitle("Scarf")
.splitViewAutosaveName("ScarfMainSidebar")
.splitViewAutosaveName("ScarfMainSidebar.\(serverContext.id)")
}
}