Skip to content

Commit 341db6a

Browse files
v0id-userclaude
andcommitted
Rename to setmac, fix UI hang and double window
- Rename project from rig to setmac (rig conflicts with R Installation Manager) - Fix Window instead of WindowGroup to prevent multiple app instances - Fix CLIBridge: null stdin, use async bytes.lines instead of blocking availableData loop — fixes UI hanging on "Checking tools..." forever - Fix struct name to match filename (SetmacApp) Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 1623243 commit 341db6a

28 files changed

Lines changed: 92 additions & 117 deletions

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
run: uv sync
3030
- name: Verify imports
3131
working-directory: cli
32-
run: uv run python -c "from rig.cli import main; print('CLI imports OK')"
32+
run: uv run python -c "from setmac.cli import main; print('CLI imports OK')"
3333
- name: Verify registry loads
3434
working-directory: cli
35-
run: uv run python -c "from rig.registry import Registry; r = Registry(); print(f'Loaded {len(r.tools)} tools')"
35+
run: uv run python -c "from setmac.registry import Registry; r = Registry(); print(f'Loaded {len(r.tools)} tools')"

Makefile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
APP_NAME := Rig
2-
BUNDLE_ID := com.v0id.rig
1+
APP_NAME := Setmac
2+
BUNDLE_ID := com.v0id.setmac
33
VERSION := 1.0.0
44
BUILD_DIR := .build
55
RELEASE_DIR := dist
@@ -44,7 +44,7 @@ cli-setup: ## Set up Python CLI dev environment
4444

4545
.PHONY: cli-dev
4646
cli-dev: ## Run CLI in dev mode
47-
cd $(CLI_DIR) && uv run rig --help
47+
cd $(CLI_DIR) && uv run setmac --help
4848

4949
.PHONY: cli-build
5050
cli-build: ## Build standalone CLI binary with PyInstaller
@@ -54,15 +54,15 @@ cli-build: ## Build standalone CLI binary with PyInstaller
5454

5555
.PHONY: status
5656
status: ## Check install status of all tools
57-
cd $(CLI_DIR) && uv run rig status
57+
cd $(CLI_DIR) && uv run setmac status
5858

5959
.PHONY: capture-configs
6060
capture-configs: ## Capture current system configs into bundle
61-
cd $(CLI_DIR) && uv run rig configs capture
61+
cd $(CLI_DIR) && uv run setmac configs capture
6262

6363
.PHONY: apply-configs
6464
apply-configs: ## Apply bundled configs to system
65-
cd $(CLI_DIR) && uv run rig configs apply
65+
cd $(CLI_DIR) && uv run setmac configs apply
6666

6767
# ─── Icon ─────────────────────────────────────────────────────
6868

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
import PackageDescription
44

55
let package = Package(
6-
name: "Rig",
6+
name: "Setmac",
77
platforms: [.macOS(.v26)],
88
targets: [
99
.executableTarget(
10-
name: "Rig",
10+
name: "Setmac",
1111
path: "Sources",
1212
resources: [
1313
.process("../Resources/Assets.xcassets"),

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Rig
1+
# setmac
22

33
Idempotent macOS setup automator. Reinstall all your dev tools, apps, and configs after a fresh format — one click or one command.
44

@@ -13,7 +13,7 @@ Idempotent macOS setup automator. Reinstall all your dev tools, apps, and config
1313
## Architecture
1414

1515
```
16-
rig/
16+
setmac/
1717
├── Sources/ # SwiftUI macOS app
1818
├── cli/ # Python CLI (uv + click)
1919
├── Resources/
@@ -34,10 +34,10 @@ make dev
3434

3535
# Or use the CLI directly
3636
cd cli && uv sync
37-
uv run rig status # Check what's installed
38-
uv run rig install all # Install everything
39-
uv run rig configs capture # Save current dotfiles
40-
uv run rig configs apply # Restore dotfiles on fresh Mac
37+
uv run setmac status # Check what's installed
38+
uv run setmac install all # Install everything
39+
uv run setmac configs capture # Save current dotfiles
40+
uv run setmac configs apply # Restore dotfiles on fresh Mac
4141
```
4242

4343
## Requirements

Resources/Info.plist

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@
33
<plist version="1.0">
44
<dict>
55
<key>CFBundleName</key>
6-
<string>Rig</string>
6+
<string>Setmac</string>
77
<key>CFBundleDisplayName</key>
8-
<string>Rig</string>
8+
<string>Setmac</string>
99
<key>CFBundleIdentifier</key>
10-
<string>com.v0id.rig</string>
10+
<string>com.v0id.setmac</string>
1111
<key>CFBundleVersion</key>
1212
<string>1</string>
1313
<key>CFBundleShortVersionString</key>
1414
<string>1.0.0</string>
1515
<key>CFBundlePackageType</key>
1616
<string>APPL</string>
1717
<key>CFBundleExecutable</key>
18-
<string>Rig</string>
18+
<string>Setmac</string>
1919
<key>CFBundleIconFile</key>
2020
<string>AppIcon</string>
2121
<key>CFBundleIconName</key>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import SwiftUI
22

33
@main
4-
struct DevToolApp: App {
4+
struct SetmacApp: App {
55
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
66

77
var body: some Scene {
8-
WindowGroup {
8+
Window("setmac", id: "main") {
99
ContentView()
1010
}
1111
.windowStyle(.automatic)

Sources/Navigation/SidebarView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ struct SidebarView: View {
3939
sidebarRow(.about)
4040
}
4141
}
42-
.navigationTitle("Rig")
42+
.navigationTitle("setmac")
4343
}
4444

4545
@ViewBuilder

Sources/Services/CLIBridge.swift

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,25 @@
11
import Foundation
22

33
actor CLIBridge {
4-
private let projectRoot: URL
5-
6-
init() {
7-
// In dev mode, project root is the working directory
8-
// In bundle mode, it's relative to the executable
9-
if let bundledCLI = Bundle.main.executableURL?
10-
.deletingLastPathComponent()
11-
.appendingPathComponent("rig"),
12-
FileManager.default.fileExists(atPath: bundledCLI.path) {
13-
projectRoot = Bundle.main.bundleURL
14-
.appendingPathComponent("Contents")
15-
.appendingPathComponent("Resources")
16-
} else {
17-
// Dev mode: assume we're running from project root
18-
projectRoot = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
19-
}
20-
}
214

225
func runCommand(_ args: [String]) -> AsyncStream<CLIMessage> {
236
AsyncStream { continuation in
247
Task.detached {
258
do {
269
let process = Process()
27-
let pipe = Pipe()
10+
let stdoutPipe = Pipe()
2811

2912
// Try bundled binary first, fall back to uv run
3013
let bundledCLI = Bundle.main.executableURL?
3114
.deletingLastPathComponent()
32-
.appendingPathComponent("rig")
15+
.appendingPathComponent("setmac")
3316

3417
if let cli = bundledCLI, FileManager.default.fileExists(atPath: cli.path) {
3518
process.executableURL = cli
3619
process.arguments = args
3720
} else {
3821
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
39-
process.arguments = ["uv", "run", "--project", "cli", "rig"] + args
22+
process.arguments = ["uv", "run", "--project", "cli", "setmac"] + args
4023
process.currentDirectoryURL = URL(
4124
fileURLWithPath: FileManager.default.currentDirectoryPath
4225
)
@@ -48,36 +31,28 @@ actor CLIBridge {
4831
"/opt/homebrew/bin",
4932
"/opt/homebrew/sbin",
5033
"/usr/local/bin",
34+
NSHomeDirectory() + "/.local/bin",
5135
NSHomeDirectory() + "/.bun/bin",
5236
NSHomeDirectory() + "/.cargo/bin",
53-
NSHomeDirectory() + "/.local/bin",
5437
]
5538
let currentPath = env["PATH"] ?? "/usr/bin:/bin"
5639
env["PATH"] = extraPaths.joined(separator: ":") + ":" + currentPath
5740
process.environment = env
5841

59-
process.standardOutput = pipe
42+
process.standardOutput = stdoutPipe
6043
process.standardError = FileHandle.nullDevice
44+
process.standardInput = FileHandle.nullDevice
6145

6246
try process.run()
6347

64-
let handle = pipe.fileHandleForReading
65-
var buffer = Data()
66-
67-
while true {
68-
let chunk = handle.availableData
69-
if chunk.isEmpty { break }
70-
buffer.append(chunk)
71-
72-
// Process complete lines
73-
while let newlineRange = buffer.range(of: Data("\n".utf8)) {
74-
let lineData = buffer.subdata(in: buffer.startIndex..<newlineRange.lowerBound)
75-
buffer.removeSubrange(buffer.startIndex...newlineRange.lowerBound)
76-
77-
if let msg = try? JSONDecoder().decode(CLIMessage.self, from: lineData) {
78-
continuation.yield(msg)
79-
}
80-
}
48+
// Read stdout line-by-line, parse JSON
49+
let handle = stdoutPipe.fileHandleForReading
50+
for try await line in handle.bytes.lines {
51+
guard !line.isEmpty else { continue }
52+
guard let data = line.data(using: .utf8),
53+
let msg = try? JSONDecoder().decode(CLIMessage.self, from: data)
54+
else { continue }
55+
continuation.yield(msg)
8156
}
8257

8358
process.waitUntilExit()

Sources/Views/Settings/AboutView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ struct AboutView: View {
88
Image(systemName: "wrench.and.screwdriver")
99
.font(.system(size: 48))
1010
.foregroundStyle(.tint)
11-
Text("Rig")
11+
Text("setmac")
1212
.font(.title)
1313
.fontWeight(.bold)
1414
Text("macOS Setup Automator")

cli/pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
[project]
2-
name = "rig-cli"
2+
name = "setmac-cli"
33
version = "1.0.0"
4-
description = "Rig CLI — macOS setup automator"
4+
description = "setmac — macOS setup automator"
55
requires-python = ">=3.12"
66
dependencies = [
77
"click>=8.1",
88
"rich>=13.0",
99
]
1010

1111
[project.scripts]
12-
rig = "rig.cli:main"
12+
setmac = "setmac.cli:main"
1313

1414
[dependency-groups]
1515
build = [
@@ -21,4 +21,4 @@ requires = ["hatchling"]
2121
build-backend = "hatchling.build"
2222

2323
[tool.hatch.build.targets.wheel]
24-
packages = ["src/rig"]
24+
packages = ["src/setmac"]

0 commit comments

Comments
 (0)