Rename app to cmuxterm

This commit is contained in:
Lawrence Chen 2026-01-28 02:38:24 -08:00
parent 6d3bbb1577
commit 3877dc2d98
20 changed files with 97 additions and 94 deletions

View file

@ -101,9 +101,9 @@ jobs:
echo "Missing notarization secrets (APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, APPLE_TEAM_ID)" >&2
exit 1
fi
APP_PATH="build/Build/Products/Release/cmux.app"
ZIP_SUBMIT="cmux-notary.zip"
DMG_RELEASE="cmux-macos.dmg"
APP_PATH="build/Build/Products/Release/cmuxterm.app"
ZIP_SUBMIT="cmuxterm-notary.zip"
DMG_RELEASE="cmuxterm-macos.dmg"
ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" "$ZIP_SUBMIT"
xcrun notarytool submit "$ZIP_SUBMIT" --apple-id "$APPLE_ID" --team-id "$APPLE_TEAM_ID" --password "$APPLE_APP_SPECIFIC_PASSWORD" --wait
xcrun stapler staple "$APP_PATH"
@ -111,9 +111,9 @@ jobs:
spctl -a -vv --type execute "$APP_PATH"
rm -f "$ZIP_SUBMIT"
STAGING_DIR="$(mktemp -d)"
cp -R "$APP_PATH" "$STAGING_DIR/cmux.app"
cp -R "$APP_PATH" "$STAGING_DIR/cmuxterm.app"
ln -s /Applications "$STAGING_DIR/Applications"
hdiutil create -volname "cmux" -srcfolder "$STAGING_DIR" -ov -format UDZO "$DMG_RELEASE"
hdiutil create -volname "cmuxterm" -srcfolder "$STAGING_DIR" -ov -format UDZO "$DMG_RELEASE"
rm -rf "$STAGING_DIR"
xcrun notarytool submit "$DMG_RELEASE" --apple-id "$APPLE_ID" --team-id "$APPLE_TEAM_ID" --password "$APPLE_APP_SPECIFIC_PASSWORD" --wait
xcrun stapler staple "$DMG_RELEASE"
@ -127,13 +127,13 @@ jobs:
echo "Missing SPARKLE_PRIVATE_KEY secret" >&2
exit 1
fi
./scripts/sparkle_generate_appcast.sh cmux-macos.dmg "$GITHUB_REF_NAME" appcast.xml
./scripts/sparkle_generate_appcast.sh cmuxterm-macos.dmg "$GITHUB_REF_NAME" appcast.xml
- name: Upload release asset
uses: softprops/action-gh-release@v2
with:
files: |
cmux-macos.dmg
cmuxterm-macos.dmg
appcast.xml
generate_release_notes: true

View file

@ -1,4 +1,4 @@
# GhosttyTabs agent notes
# cmuxterm agent notes
## Local dev
@ -11,17 +11,19 @@ xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug -des
`reload` = kill and launch the Debug app only:
```bash
pkill -x "cmux DEV" || true
sleep 0.2
open /Users/lawrencechen/Library/Developer/Xcode/DerivedData/GhosttyTabs-cbjivvtpirygxbbgqlpdpiiyjnwh/Build/Products/Debug/cmux\ DEV.app
./scripts/reload.sh
```
`reload-prod` = kill and launch the Release app:
`reloadp` = kill and launch the Release app:
```bash
pkill -x cmux || true
sleep 0.2
open /Users/lawrencechen/Library/Developer/Xcode/DerivedData/GhosttyTabs-cbjivvtpirygxbbgqlpdpiiyjnwh/Build/Products/Release/cmux.app
./scripts/reloadp.sh
```
`reload2` = reload both Debug and Release:
```bash
./scripts/reload2.sh
```
## Release
@ -31,12 +33,12 @@ Tagging a version triggers the GitHub Actions release workflow and uploads the n
```bash
git tag vX.Y.Z
git push origin vX.Y.Z
gh run watch --repo manaflow-ai/GhosttyTabs
gh run watch --repo manaflow-ai/cmuxterm
```
Notes:
- Requires GitHub secrets: `APPLE_CERTIFICATE_BASE64`, `APPLE_CERTIFICATE_PASSWORD`,
`APPLE_SIGNING_IDENTITY`, `APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`, `APPLE_TEAM_ID`.
- The release asset is `cmux-macos.dmg` attached to the tag.
- README download button points to `releases/latest/download/cmux-macos.dmg`.
- The release asset is `cmuxterm-macos.dmg` attached to the tag.
- README download button points to `releases/latest/download/cmuxterm-macos.dmg`.
- Versioning: bump the minor version for updates unless explicitly asked otherwise.

View file

@ -64,7 +64,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
A5001000 /* cmux.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = cmux.app; sourceTree = BUILT_PRODUCTS_DIR; };
A5001000 /* cmuxterm.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = cmuxterm.app; sourceTree = BUILT_PRODUCTS_DIR; };
7E7E6EF344A568AC7FEE3715 /* GhosttyTabsUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GhosttyTabsUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
A5001011 /* cmuxApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = cmuxApp.swift; sourceTree = "<group>"; };
A5001012 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@ -196,7 +196,7 @@
A5001042 /* Products */ = {
isa = PBXGroup;
children = (
A5001000 /* cmux.app */,
A5001000 /* cmuxterm.app */,
7E7E6EF344A568AC7FEE3715 /* GhosttyTabsUITests.xctest */,
);
name = Products;
@ -232,7 +232,7 @@
);
name = GhosttyTabs;
productName = GhosttyTabs;
productReference = A5001000 /* cmux.app */;
productReference = A5001000 /* cmuxterm.app */;
productType = "com.apple.product-type.application";
};
CB450DF0F0B3839599082C4D /* GhosttyTabsUITests */ = {
@ -406,23 +406,23 @@
CODE_SIGN_ENTITLEMENTS = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = NO;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "cmux DEV";
INFOPLIST_KEY_CFBundleName = "cmux DEV";
INFOPLIST_KEY_CFBundleDisplayName = "cmuxterm DEV";
INFOPLIST_KEY_CFBundleName = "cmuxterm DEV";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSMainStoryboardFile = "";
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
INFOPLIST_KEY_SUFeedURL = "https://github.com/manaflow-ai/GhosttyTabs/releases/latest/download/appcast.xml";
INFOPLIST_KEY_SUFeedURL = "https://github.com/manaflow-ai/cmuxterm/releases/latest/download/appcast.xml";
INFOPLIST_KEY_SUPublicEDKey = "$(SPARKLE_PUBLIC_KEY)";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.1.0;
MARKETING_VERSION = 1.2.0;
OTHER_LDFLAGS = (
"-lc++",
"-framework",
@ -436,8 +436,8 @@
"-framework",
Carbon,
);
PRODUCT_BUNDLE_IDENTIFIER = com.cmux.app.debug;
PRODUCT_NAME = "cmux DEV";
PRODUCT_BUNDLE_IDENTIFIER = com.cmuxterm.app.debug;
PRODUCT_NAME = "cmuxterm DEV";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "cmux-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@ -451,23 +451,23 @@
CODE_SIGN_ENTITLEMENTS = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = NO;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = cmux;
INFOPLIST_KEY_CFBundleName = cmux;
INFOPLIST_KEY_CFBundleDisplayName = cmuxterm;
INFOPLIST_KEY_CFBundleName = cmuxterm;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSMainStoryboardFile = "";
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
INFOPLIST_KEY_SUFeedURL = "https://github.com/manaflow-ai/GhosttyTabs/releases/latest/download/appcast.xml";
INFOPLIST_KEY_SUFeedURL = "https://github.com/manaflow-ai/cmuxterm/releases/latest/download/appcast.xml";
INFOPLIST_KEY_SUPublicEDKey = "$(SPARKLE_PUBLIC_KEY)";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.1.0;
MARKETING_VERSION = 1.2.0;
OTHER_LDFLAGS = (
"-lc++",
"-framework",
@ -482,8 +482,8 @@
Carbon,
);
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.cmux.app;
PRODUCT_NAME = cmux;
PRODUCT_BUNDLE_IDENTIFIER = com.cmuxterm.app;
PRODUCT_NAME = cmuxterm;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "cmux-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@ -494,12 +494,12 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.1.0;
MARKETING_VERSION = 1.2.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.cmux.appuitests;
PRODUCT_BUNDLE_IDENTIFIER = com.cmuxterm.appuitests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_VERSION = 5.0;
@ -511,12 +511,12 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.1.0;
MARKETING_VERSION = 1.2.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.cmux.appuitests;
PRODUCT_BUNDLE_IDENTIFIER = com.cmuxterm.appuitests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_TARGET_NAME = GhosttyTabs;

View file

@ -3,7 +3,7 @@
<BuildAction parallelizeBuildables="YES" buildImplicitDependencies="YES">
<BuildActionEntries>
<BuildActionEntry buildForTesting="YES" buildForRunning="YES" buildForProfiling="YES" buildForArchiving="YES" buildForAnalyzing="YES">
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="A5001050" BuildableName="cmux.app" BlueprintName="GhosttyTabs" ReferencedContainer="container:GhosttyTabs.xcodeproj"/>
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="A5001050" BuildableName="cmuxterm.app" BlueprintName="GhosttyTabs" ReferencedContainer="container:GhosttyTabs.xcodeproj"/>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
@ -14,17 +14,17 @@
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="A5001050" BuildableName="cmux.app" BlueprintName="GhosttyTabs" ReferencedContainer="container:GhosttyTabs.xcodeproj"/>
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="A5001050" BuildableName="cmuxterm.app" BlueprintName="GhosttyTabs" ReferencedContainer="container:GhosttyTabs.xcodeproj"/>
</MacroExpansion>
</TestAction>
<LaunchAction buildConfiguration="Release" selectedDebuggerIdentifier="Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier="Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle="0" useCustomWorkingDirectory="NO" ignoresPersistentStateOnLaunch="NO" debugDocumentVersioning="YES" allowLocationSimulation="YES">
<BuildableProductRunnable runnableDebuggingMode="0">
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="A5001050" BuildableName="cmux.app" BlueprintName="GhosttyTabs" ReferencedContainer="container:GhosttyTabs.xcodeproj"/>
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="A5001050" BuildableName="cmuxterm.app" BlueprintName="GhosttyTabs" ReferencedContainer="container:GhosttyTabs.xcodeproj"/>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction buildConfiguration="Release" shouldUseLaunchSchemeArgsEnv="YES" savedToolIdentifier="" useCustomWorkingDirectory="NO" debugDocumentVersioning="YES">
<BuildableProductRunnable runnableDebuggingMode="0">
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="A5001050" BuildableName="cmux.app" BlueprintName="GhosttyTabs" ReferencedContainer="container:GhosttyTabs.xcodeproj"/>
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="A5001050" BuildableName="cmuxterm.app" BlueprintName="GhosttyTabs" ReferencedContainer="container:GhosttyTabs.xcodeproj"/>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction buildConfiguration="Release"/>

View file

@ -1,22 +1,22 @@
# cmux
# cmuxterm
Vertical tabs for Ghostty on macOS, built on libghostty.
[![Download macOS](https://img.shields.io/badge/Download-macOS-1b5fdd?style=for-the-badge&logo=apple)](releases/latest/download/cmux-macos.dmg)
[![Download macOS](https://img.shields.io/badge/Download-macOS-1b5fdd?style=for-the-badge&logo=apple)](releases/latest/download/cmuxterm-macos.dmg)
## Releases
Tag a version like `v0.1.0` and push it to trigger the GitHub Actions release workflow.
The workflow builds `GhosttyKit.xcframework`, builds the Release app, signs, notarizes,
staples, and uploads `cmux-macos.dmg` to the release.
staples, and uploads `cmuxterm-macos.dmg` to the release.
## Auto updates
cmux uses Sparkle with the same update UI flow as upstream Ghostty. The app looks for
cmuxterm uses Sparkle with the same update UI flow as upstream Ghostty. The app looks for
an appcast at:
```
https://github.com/manaflow-ai/GhosttyTabs/releases/latest/download/appcast.xml
https://github.com/manaflow-ai/cmuxterm/releases/latest/download/appcast.xml
```
To sign updates, set these secrets for release builds:
@ -36,7 +36,7 @@ to `.env`), run:
For manual appcast generation (uses `SPARKLE_PRIVATE_KEY`):
```bash
SPARKLE_PRIVATE_KEY=... ./scripts/sparkle_generate_appcast.sh cmux-macos.dmg vX.Y.Z appcast.xml
SPARKLE_PRIVATE_KEY=... ./scripts/sparkle_generate_appcast.sh cmuxterm-macos.dmg vX.Y.Z appcast.xml
```
### Required GitHub secrets

View file

@ -422,13 +422,13 @@ class TabManager: ObservableObject {
}
private func windowTitle(for tab: Tab?) -> String {
guard let tab else { return "cmux" }
guard let tab else { return "cmuxterm" }
let trimmedTitle = tab.title.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmedTitle.isEmpty {
return trimmedTitle
}
let trimmedDirectory = tab.currentDirectory.trimmingCharacters(in: .whitespacesAndNewlines)
return trimmedDirectory.isEmpty ? "cmux" : trimmedDirectory
return trimmedDirectory.isEmpty ? "cmuxterm" : trimmedDirectory
}
func focusTab(_ tabId: UUID, surfaceId: UUID? = nil) {

View file

@ -15,8 +15,8 @@ struct TerminalNotification: Identifiable, Hashable {
final class TerminalNotificationStore: ObservableObject {
static let shared = TerminalNotificationStore()
static let categoryIdentifier = "com.cmux.app.userNotification"
static let actionShowIdentifier = "com.cmux.app.userNotification.show"
static let categoryIdentifier = "com.cmuxterm.app.userNotification"
static let actionShowIdentifier = "com.cmuxterm.app.userNotification.show"
@Published private(set) var notifications: [TerminalNotification] = []
@ -107,7 +107,7 @@ final class TerminalNotificationStore: ObservableObject {
let content = UNMutableNotificationContent()
let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String
?? Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String
?? "cmux"
?? "cmuxterm"
content.title = appName
content.subtitle = notification.title
content.body = notification.body
@ -173,8 +173,8 @@ final class TerminalNotificationStore: ObservableObject {
self.hasPromptedForSettings = true
let alert = NSAlert()
alert.messageText = "Enable Notifications for cmux"
alert.informativeText = "Notifications are disabled for cmux. Enable them in System Settings to see alerts."
alert.messageText = "Enable Notifications for cmuxterm"
alert.informativeText = "Notifications are disabled for cmuxterm. Enable them in System Settings to see alerts."
alert.addButton(withTitle: "Open Settings")
alert.addButton(withTitle: "Not Now")
let response = alert.runModal()

View file

@ -2,7 +2,7 @@ import Sparkle
import Cocoa
import Combine
/// Controller for managing Sparkle updates in cmux.
/// Controller for managing Sparkle updates in cmuxterm.
class UpdateController {
private(set) var updater: SPUUpdater
private let userDriver: UpdateDriver

View file

@ -4,7 +4,7 @@ import Cocoa
extension UpdateDriver: SPUUpdaterDelegate {
func feedURLString(for updater: SPUUpdater) -> String? {
let infoURL = Bundle.main.object(forInfoDictionaryKey: "SUFeedURL") as? String
let fallback = "https://github.com/manaflow-ai/GhosttyTabs/releases/latest/download/appcast.xml"
let fallback = "https://github.com/manaflow-ai/cmuxterm/releases/latest/download/appcast.xml"
let feedURLString = (infoURL?.isEmpty == false) ? infoURL! : fallback
recordFeedURLString(feedURLString, usedFallback: feedURLString == fallback)
return feedURLString

View file

@ -48,7 +48,7 @@ class UpdateDriver: NSObject, SPUUserDriver {
}
func showUpdateReleaseNotes(with downloadData: SPUDownloadData) {
// cmux uses Sparkle's UI for release notes links instead.
// cmuxterm uses Sparkle's UI for release notes links instead.
}
func showUpdateReleaseNotesFailedToDownloadWithError(_ error: any Error) {

View file

@ -4,7 +4,7 @@ import AppKit
final class UpdateLogStore {
static let shared = UpdateLogStore()
private let queue = DispatchQueue(label: "cmux.update.log")
private let queue = DispatchQueue(label: "cmuxterm.update.log")
private var entries: [String] = []
private let maxEntries = 200
private let logURL: URL
@ -15,7 +15,7 @@ final class UpdateLogStore {
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let logsDir = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first
?? FileManager.default.temporaryDirectory
logURL = logsDir.appendingPathComponent("Logs/cmux-update.log")
logURL = logsDir.appendingPathComponent("Logs/cmuxterm-update.log")
ensureLogFile()
}

View file

@ -52,7 +52,7 @@ fileprivate struct PermissionRequestView: View {
Text("Enable automatic updates?")
.font(.system(size: 13, weight: .semibold))
Text("cmux can automatically check for updates in the background.")
Text("cmuxterm can automatically check for updates in the background.")
.font(.system(size: 11))
.foregroundColor(.secondary)
.fixedSize(horizontal: false, vertical: true)

View file

@ -33,13 +33,13 @@ enum UpdateTestSupport {
private static func makeAppcastItem(displayVersion: String) -> SUAppcastItem? {
let enclosure: [String: Any] = [
"url": "https://example.com/cmux.zip",
"url": "https://example.com/cmuxterm.zip",
"length": "1024",
"sparkle:version": displayVersion,
"sparkle:shortVersionString": displayVersion,
]
let dict: [String: Any] = [
"title": "cmux \(displayVersion)",
"title": "cmuxterm \(displayVersion)",
"enclosure": enclosure,
]
return SUAppcastItem(dictionary: dict)

View file

@ -216,13 +216,13 @@ class UpdateViewModel: ObservableObject {
if let networkError = networkError(from: nsError) {
switch networkError.code {
case NSURLErrorNotConnectedToInternet:
return "cmux cant reach the update server. Check your internet connection and try again."
return "cmuxterm cant reach the update server. Check your internet connection and try again."
case NSURLErrorTimedOut:
return "The update server took too long to respond. Try again in a moment."
case NSURLErrorCannotFindHost:
return "The update server cant be found. Check your connection or try again later."
case NSURLErrorCannotConnectToHost:
return "cmux couldnt connect to the update server. Check your connection or try again later."
return "cmuxterm couldnt connect to the update server. Check your connection or try again later."
case NSURLErrorNetworkConnectionLost:
return "The network connection was lost while checking for updates. Try again."
case NSURLErrorSecureConnectionFailed,
@ -238,7 +238,7 @@ class UpdateViewModel: ObservableObject {
if nsError.domain == SUSparkleErrorDomain {
switch nsError.code {
case 2001:
return "cmux couldnt download the update feed. Check your connection and try again."
return "cmuxterm couldnt download the update feed. Check your connection and try again."
case 1000, 1002:
return "The update feed could not be read. Please try again later."
case 4:
@ -248,7 +248,7 @@ class UpdateViewModel: ObservableObject {
case 1, 2, 3001, 3002:
return "The updates signature could not be verified. Please try again later."
case 1003, 1005:
return "Move cmux into Applications and relaunch to enable updates."
return "Move cmuxterm into Applications and relaunch to enable updates."
default:
break
}
@ -437,7 +437,7 @@ enum UpdateState: Equatable {
if let semver = Self.extractSemanticVersion(from: version) {
let tag = semver.hasPrefix("v") ? semver : "v\(semver)"
if let url = URL(string: "https://github.com/manaflow-ai/GhosttyTabs/releases/tag/\(tag)") {
if let url = URL(string: "https://github.com/manaflow-ai/cmuxterm/releases/tag/\(tag)") {
self = .tagged(url)
return
}
@ -447,7 +447,7 @@ enum UpdateState: Equatable {
return nil
}
if let url = URL(string: "https://github.com/manaflow-ai/GhosttyTabs/commit/\(newHash)") {
if let url = URL(string: "https://github.com/manaflow-ai/cmuxterm/commit/\(newHash)") {
self = .commit(url)
} else {
return nil

View file

@ -26,7 +26,7 @@ struct cmuxApp: App {
.windowToolbarStyle(.automatic)
.commands {
CommandGroup(replacing: .appInfo) {
Button("About cmux") {
Button("About cmuxterm") {
showAboutPanel()
}
Divider()
@ -130,7 +130,7 @@ struct cmuxApp: App {
let bundle = Bundle.main
let appName = bundle.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String
?? bundle.object(forInfoDictionaryKey: "CFBundleName") as? String
?? "cmux"
?? "cmuxterm"
let version = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "1.0"
let build = bundle.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? "1"
NSApp.orderFrontStandardAboutPanel(options: [

View file

@ -1,6 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
pkill -x "cmux DEV" || true
xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug -destination 'platform=macOS' build
pkill -x "cmuxterm DEV" || true
sleep 0.2
open /Users/lawrencechen/Library/Developer/Xcode/DerivedData/GhosttyTabs-cbjivvtpirygxbbgqlpdpiiyjnwh/Build/Products/Debug/cmux\ DEV.app
open /Users/lawrencechen/Library/Developer/Xcode/DerivedData/GhosttyTabs-cbjivvtpirygxbbgqlpdpiiyjnwh/Build/Products/Debug/cmuxterm\ DEV.app

View file

@ -16,8 +16,8 @@ if [[ -z "${SPARKLE_PRIVATE_KEY:-}" ]]; then
fi
SPARKLE_VERSION="${SPARKLE_VERSION:-2.8.1}"
DOWNLOAD_URL_PREFIX="${DOWNLOAD_URL_PREFIX:-https://github.com/manaflow-ai/GhosttyTabs/releases/download/$TAG/}"
RELEASE_NOTES_URL="${RELEASE_NOTES_URL:-https://github.com/manaflow-ai/GhosttyTabs/releases/tag/$TAG}"
DOWNLOAD_URL_PREFIX="${DOWNLOAD_URL_PREFIX:-https://github.com/manaflow-ai/cmuxterm/releases/download/$TAG/}"
RELEASE_NOTES_URL="${RELEASE_NOTES_URL:-https://github.com/manaflow-ai/cmuxterm/releases/tag/$TAG}"
work_dir="$(mktemp -d)"
cleanup() {

View file

@ -2,7 +2,7 @@
set -euo pipefail
SPARKLE_VERSION="${SPARKLE_VERSION:-2.8.1}"
SPARKLE_KEYCHAIN_ACCOUNT="${SPARKLE_KEYCHAIN_ACCOUNT:-cmux}"
SPARKLE_KEYCHAIN_ACCOUNT="${SPARKLE_KEYCHAIN_ACCOUNT:-cmuxterm}"
SPARKLE_ENV_FILE="${SPARKLE_ENV_FILE:-.env}"
work_dir="$(mktemp -d)"

View file

@ -1,24 +1,24 @@
#!/bin/bash
# Test script that sends keystrokes to cmux via AppleScript
# Test script that sends keystrokes to cmuxterm via AppleScript
# This tests the actual keyboard input path through the app
set -e
echo "=== cmux Keystroke Test ==="
echo "=== cmuxterm Keystroke Test ==="
echo ""
# Check if cmux is running
if ! pgrep -x "cmux" > /dev/null; then
echo "Error: cmux is not running"
echo "Please start cmux first"
# Check if cmuxterm is running
if ! pgrep -x "cmuxterm" > /dev/null; then
echo "Error: cmuxterm is not running"
echo "Please start cmuxterm first"
exit 1
fi
echo "cmux is running"
echo "cmuxterm is running"
echo ""
# Activate cmux
osascript -e 'tell application "cmux" to activate'
# Activate cmuxterm
osascript -e 'tell application "cmuxterm" to activate'
sleep 0.5
echo "Test 1: Testing Ctrl+C (SIGINT)"
@ -56,7 +56,7 @@ echo " If cat exited, Ctrl+D is working!"
echo ""
echo "=== Manual Verification Required ==="
echo "Please check the cmux window to verify:"
echo "Please check the cmuxterm window to verify:"
echo " 1. The 'sleep 30' command was interrupted by Ctrl+C"
echo " 2. The 'cat' command exited after Ctrl+D"
echo ""

View file

@ -3,7 +3,7 @@
Automated test for ctrl+enter keybind using real keystrokes.
Requires:
- cmux running
- cmuxterm running
- Accessibility permissions for System Events (osascript)
- keybind = ctrl+enter=text:\\r (or \\n/\\x0d) configured in Ghostty config
"""
@ -64,7 +64,7 @@ def test_ctrl_enter_keybind(client: cmux) -> tuple[bool, str]:
time.sleep(0.3)
# Make sure the app is focused for keystrokes
run_osascript('tell application "cmux" to activate')
run_osascript('tell application "cmuxterm" to activate')
time.sleep(0.2)
# Clear any running command
@ -94,14 +94,14 @@ def test_ctrl_enter_keybind(client: cmux) -> tuple[bool, str]:
def run_tests() -> int:
print("=" * 60)
print("cmux Ctrl+Enter Keybind Test")
print("cmuxterm Ctrl+Enter Keybind Test")
print("=" * 60)
print()
socket_path = cmux.DEFAULT_SOCKET_PATH
if not os.path.exists(socket_path):
print(f"Error: Socket not found at {socket_path}")
print("Please make sure cmux is running.")
print("Please make sure cmuxterm is running.")
return 1
config_path = find_config_with_keybind()
@ -109,7 +109,7 @@ def run_tests() -> int:
print("Error: Required keybind not found in Ghostty config.")
print("Add a line like:")
print(" keybind = ctrl+enter=text:\\r")
print("Then restart cmux and re-run this test.")
print("Then restart cmuxterm and re-run this test.")
return 1
print(f"Using keybind from: {config_path}")