diff --git a/.github/workflows/release-trigger.yml b/.github/workflows/release-trigger.yml
deleted file mode 100644
index a64b248..0000000
--- a/.github/workflows/release-trigger.yml
+++ /dev/null
@@ -1,87 +0,0 @@
-name: Release Trigger
-
-# UI-driven releases: pick a bump type, this workflow bumps the version in
-# the codebase, commits it, pushes a vX.Y.Z tag โ and the tag push runs the
-# existing `Release` workflow, which builds, attaches assets, and publishes
-# the release with auto-generated notes.
-
-on:
- workflow_dispatch:
- inputs:
- bump_type:
- description: 'Version bump'
- type: choice
- required: true
- default: 'patch'
- options:
- - major
- - minor
- - patch
- - none
-
-permissions:
- contents: write
-
-jobs:
- bump-and-tag:
- name: Bump version & push tag
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- with:
- ref: ${{ github.ref }}
- fetch-depth: 0
-
- - name: Configure git (github-actions bot)
- run: |
- git config user.name "github-actions[bot]"
- git config user.email "github-actions[bot]@users.noreply.github.com"
-
- - name: Compute new version
- id: version
- run: |
- chmod +x Scripts/bump_version.sh
- NEW_VERSION="$(Scripts/bump_version.sh "${{ inputs.bump_type }}")"
- echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
- echo "tag=v$NEW_VERSION" >> "$GITHUB_OUTPUT"
- echo "Releasing v$NEW_VERSION (bump: ${{ inputs.bump_type }})"
-
- - name: Guard โ tag must not already exist
- run: |
- if git rev-parse "refs/tags/${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
- echo "::error::Tag ${{ steps.version.outputs.tag }} already exists. Use bump type 'none' only for re-releases of a version whose tag was deleted."
- exit 1
- fi
-
- - name: Commit version bump
- run: |
- git add Sources/ClapCLIKit/ClapCLI.swift \
- Sources/ClapApp/SettingsView.swift \
- Scripts/Info.plist
- if git diff --cached --quiet; then
- if [ "${{ inputs.bump_type }}" != "none" ]; then
- echo "::error::Version bump changed nothing โ unexpected."
- exit 1
- fi
- echo "No version change for bump type 'none'."
- else
- git commit -m "Bump version to ${{ steps.version.outputs.tag }}"
- fi
-
- - name: Push commit and tag
- run: |
- git push origin "HEAD:${{ github.ref_name }}"
- git tag "${{ steps.version.outputs.tag }}"
- git push origin "${{ steps.version.outputs.tag }}"
-
- - name: Summary
- run: |
- {
- echo "## Release triggered ๐"
- echo "- Tag: \`${{ steps.version.outputs.tag }}\`"
- echo "- Bump: \`${{ inputs.bump_type }}\`"
- echo "- The \`Release\` workflow is now building assets; the GitHub"
- echo " release will appear with auto-generated notes when it finishes."
- } >> "$GITHUB_STEP_SUMMARY"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 476b687..f2322fa 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,21 +1,67 @@
name: Release
on:
- push:
- tags:
- - 'v*'
+ workflow_dispatch:
+ inputs:
+ bump_type:
+ description: 'Version bump'
+ type: choice
+ required: true
+ default: 'patch'
+ options:
+ - major
+ - minor
+ - patch
+ - none
permissions:
contents: write
jobs:
- build-and-release:
- # macOS 26 SDK is required to compile NSGlassEffectView (Liquid Glass).
+ release:
+ name: Bump, build & publish
runs-on: macos-26
steps:
- - name: Checkout repository
+ - name: Checkout
uses: actions/checkout@v4
+ with:
+ ref: ${{ github.ref }}
+ fetch-depth: 0
+
+ - name: Configure git (github-actions bot)
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+
+ - name: Compute new version
+ id: version
+ run: |
+ chmod +x Scripts/bump_version.sh
+ NEW_VERSION="$(Scripts/bump_version.sh "${{ inputs.bump_type }}")"
+ echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
+ echo "tag=v$NEW_VERSION" >> "$GITHUB_OUTPUT"
+ echo "Releasing v$NEW_VERSION (bump: ${{ inputs.bump_type }})"
+
+ - name: Guard โ tag must not already exist
+ run: |
+ if git rev-parse "refs/tags/${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
+ echo "::error::Tag ${{ steps.version.outputs.tag }} already exists."
+ exit 1
+ fi
+
+ - name: Commit version bump
+ run: |
+ git add Sources/ClapCore/ClapVersion.swift
+ if git diff --cached --quiet; then
+ if [ "${{ inputs.bump_type }}" != "none" ]; then
+ echo "::error::Version bump changed nothing โ unexpected."
+ exit 1
+ fi
+ echo "No version change for bump type 'none'."
+ else
+ git commit -m "Bump version to ${{ steps.version.outputs.tag }}"
+ fi
- name: Select Xcode
uses: maxim-lobanov/setup-xcode@v1
@@ -29,21 +75,37 @@ jobs:
run: |
chmod +x Scripts/make_app.sh
./Scripts/make_app.sh dist
-
- TAG_NAME="${GITHUB_REF#refs/tags/}"
+
+ TAG_NAME="${{ steps.version.outputs.tag }}"
ZIP_NAME="clap-${TAG_NAME}.zip"
-
+
cd dist
zip -r -y "../${ZIP_NAME}" clap.app
cd ..
shasum -a 256 "${ZIP_NAME}" > "${ZIP_NAME}.sha256"
+ - name: Push commit and tag (only after a successful build)
+ run: |
+ git push origin "HEAD:${{ github.ref_name }}"
+ git tag "${{ steps.version.outputs.tag }}"
+ git push origin "${{ steps.version.outputs.tag }}"
+
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
+ tag_name: ${{ steps.version.outputs.tag }}
files: |
clap-*.zip
clap-*.zip.sha256
draft: false
prerelease: false
generate_release_notes: true
+
+ - name: Summary
+ run: |
+ {
+ echo "## Release published ๐"
+ echo "- Tag: \`${{ steps.version.outputs.tag }}\`"
+ echo "- Bump: \`${{ inputs.bump_type }}\`"
+ echo "- Assets: zip + sha256 attached to the GitHub Release."
+ } >> "$GITHUB_STEP_SUMMARY"
diff --git a/Scripts/Info.plist b/Scripts/Info.plist
index 6b5967f..23b91a6 100644
--- a/Scripts/Info.plist
+++ b/Scripts/Info.plist
@@ -13,7 +13,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 0.2.1
+ 0.0.0-PLACEHOLDER
CFBundleVersion
5
LSMinimumSystemVersion
diff --git a/Scripts/bump_version.sh b/Scripts/bump_version.sh
index 6a7233d..5ca290c 100755
--- a/Scripts/bump_version.sh
+++ b/Scripts/bump_version.sh
@@ -9,8 +9,8 @@ if [[ ! "$BUMP" =~ ^(major|minor|patch|none)$ ]]; then
exit 2
fi
-CLI_FILE="Sources/ClapCLIKit/ClapCLI.swift"
-CURRENT="$(sed -n 's/^ public static let version = "\([0-9]*\.[0-9]*\.[0-9]*\)"/\1/p' "$CLI_FILE")"
+CLI_FILE="Sources/ClapCore/ClapVersion.swift"
+CURRENT="$(sed -n 's/^ public static let current = "\([0-9]*\.[0-9]*\.[0-9]*\)"/\1/p' "$CLI_FILE")"
if [[ -z "$CURRENT" ]]; then
echo "error: could not read current version from $CLI_FILE" >&2
exit 1
@@ -35,8 +35,5 @@ substitute_inplace() {
sed "$pattern" "$file" > "$file.tmp" && mv "$file.tmp" "$file"
}
-substitute_inplace "s/public static let version = \"$CURRENT\"/public static let version = \"$NEW\"/" "$CLI_FILE"
-substitute_inplace "s/clipboard & shell history manager ยท v$CURRENT/clipboard & shell history manager ยท v$NEW/" \
- Sources/ClapApp/SettingsView.swift
-substitute_inplace "s/$CURRENT<\/string>/$NEW<\/string>/" Scripts/Info.plist
+substitute_inplace "s/public static let current = \"$CURRENT\"/public static let current = \"$NEW\"/" "$CLI_FILE"
echo "$NEW"
diff --git a/Scripts/make_app.sh b/Scripts/make_app.sh
index 6c058b7..3348ad7 100755
--- a/Scripts/make_app.sh
+++ b/Scripts/make_app.sh
@@ -16,7 +16,14 @@ rm -rf "$APP"
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources"
cp "$BIN/ClapApp" "$APP/Contents/MacOS/ClapApp"
cp "$BIN/clap" "$APP/Contents/MacOS/clap"
-cp "$ROOT/Scripts/Info.plist" "$APP/Contents/Info.plist"
+APP_VERSION="$(sed -n 's/^ public static let current = "\([0-9.]*\)"/\1/p' \
+ "$ROOT/Sources/ClapCore/ClapVersion.swift")"
+if [ -z "$APP_VERSION" ]; then
+ echo "error: could not read version from ClapVersion.swift" >&2
+ exit 1
+fi
+sed "s|0\.0\.0-PLACEHOLDER|$APP_VERSION|" \
+ "$ROOT/Scripts/Info.plist" > "$APP/Contents/Info.plist"
if [ -d "$ROOT/Resources" ]; then
cp -R "$ROOT/Resources/"* "$APP/Contents/Resources/" 2>/dev/null || true
fi
diff --git a/Sources/ClapApp/AppState+Pasteboard.swift b/Sources/ClapApp/AppState+Pasteboard.swift
index 1ee059d..b0dad14 100644
--- a/Sources/ClapApp/AppState+Pasteboard.swift
+++ b/Sources/ClapApp/AppState+Pasteboard.swift
@@ -86,7 +86,7 @@ extension AppState {
pasteboard.clearContents()
pasteboard.setString(text, forType: .string)
await self.perform("Capture transformed text") {
- try await self.store.captureText(text, sourceApp: "clap")
+ try await self.store.captureText(text, sourceApp: ClapIdentity.bundleID)
}
IPC.post(.storeChanged)
self.reload()
diff --git a/Sources/ClapApp/PreviewPanel.swift b/Sources/ClapApp/PreviewPanel.swift
index 6818795..28f8a2b 100644
--- a/Sources/ClapApp/PreviewPanel.swift
+++ b/Sources/ClapApp/PreviewPanel.swift
@@ -445,7 +445,17 @@ struct PreviewView: View {
guard let url = NSWorkspace.shared.urlForApplication(withBundleIdentifier: bundleID) else {
return bundleID
}
- return FileManager.default.displayName(atPath: url.path)
+ // Prefer the bundle's localized display name; the on-disk name
+ // carries a ".app" suffix nobody wants in the UI.
+ if let bundle = Bundle(url: url) {
+ if let displayName = bundle.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String {
+ return displayName
+ }
+ if let name = bundle.object(forInfoDictionaryKey: "CFBundleName") as? String {
+ return name
+ }
+ }
+ return url.deletingPathExtension().lastPathComponent
}
}
diff --git a/Sources/ClapApp/SettingsView.swift b/Sources/ClapApp/SettingsView.swift
index a22e4b0..ab195eb 100644
--- a/Sources/ClapApp/SettingsView.swift
+++ b/Sources/ClapApp/SettingsView.swift
@@ -122,7 +122,7 @@ struct SettingsView: View {
VStack(alignment: .leading, spacing: 2) {
Text("Clap")
.font(.title2.weight(.bold))
- Text("Local-first clipboard & shell history manager ยท v0.2.1")
+ Text("Local-first clipboard & shell history manager ยท v\(ClapVersion.current)")
.font(.system(size: 11))
.foregroundStyle(.secondary)
}
diff --git a/Sources/ClapCLIKit/ClapCLI.swift b/Sources/ClapCLIKit/ClapCLI.swift
index 0ff38ee..62e5dc9 100644
--- a/Sources/ClapCLIKit/ClapCLI.swift
+++ b/Sources/ClapCLIKit/ClapCLI.swift
@@ -1,4 +1,5 @@
import Foundation
+import ClapCore
/// clap โ clipboard manager CLI dispatcher.
///
@@ -6,7 +7,7 @@ import Foundation
/// Global flags (`--data-dir `) are accepted anywhere on the line and
/// extracted before command dispatch.
public enum ClapCLI {
- public static let version = "0.2.1"
+ public static var version: String { ClapVersion.current }
/// Command dispatch table. Hidden/scripting commands are marked in help
/// comments only.
diff --git a/Sources/ClapCore/ClapVersion.swift b/Sources/ClapCore/ClapVersion.swift
new file mode 100644
index 0000000..37fe6fc
--- /dev/null
+++ b/Sources/ClapCore/ClapVersion.swift
@@ -0,0 +1,10 @@
+/// Single source of truth for the release version.
+///
+/// Everything else derives from here:
+/// - CLI `--version` and the Settings header read `ClapVersion.current`.
+/// - `Scripts/make_app.sh` injects it into Info.plist's
+/// CFBundleShortVersionString at packaging time.
+/// - `Scripts/bump_version.sh` updates ONLY this file.
+public enum ClapVersion {
+ public static let current = "0.2.0"
+}