Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
lfs: true

- name: Select Xcode
id: toolchain
Expand All @@ -25,7 +28,9 @@ jobs:
fi

swift --version
XCODE_VERSION="$(xcodebuild -version | awk '/^Xcode / { print $2; exit }')"
XCODE_BUILD_VERSION="$(xcodebuild -version)"
printf '%s\n' "$XCODE_BUILD_VERSION"
XCODE_VERSION="$(printf '%s\n' "$XCODE_BUILD_VERSION" | awk '/^Xcode / { print $2 }')"
echo "xcode_version=$XCODE_VERSION" >> "$GITHUB_OUTPUT"

SDK_VERSION="$(xcrun --sdk macosx --show-sdk-version || echo 0)"
Expand All @@ -40,14 +45,48 @@ jobs:
${{ runner.os }}-xcode-${{ steps.toolchain.outputs.xcode_version }}-spm-
${{ runner.os }}-spm-

- name: Verify Ghostty archive
run: |
set -euo pipefail
ARCHIVE="Frameworks/GhosttyKit.xcframework/macos-arm64/libghostty-fat.a"
test -f "$ARCHIVE"
file "$ARCHIVE"
ar -t "$ARCHIVE" >/dev/null

- name: Build
run: |
swift build

- name: Run SwiftLint
run: |
set -euo pipefail
brew install swiftlint
swiftlint lint Sources/

if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE_SHA="${{ github.event.pull_request.base.sha }}"
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
else
BASE_SHA="${{ github.event.before }}"
HEAD_SHA="${{ github.sha }}"
fi

if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then
SWIFT_FILES="$(find Sources -name '*.swift' -print | sort)"
else
SWIFT_FILES="$(git diff --name-only --diff-filter=ACMR "$BASE_SHA" "$HEAD_SHA" | grep '^Sources/.*\.swift$' || true)"
fi

if [ -z "$SWIFT_FILES" ]; then
echo "No changed Swift source files to lint."
exit 0
fi

FILE_COUNT="$(printf '%s\n' "$SWIFT_FILES" | sed '/^$/d' | wc -l | tr -d ' ')"
printf 'Linting %s changed Swift files\n' "$FILE_COUNT"
printf '%s\n' "$SWIFT_FILES" | while IFS= read -r file; do
[ -n "$file" ] || continue
swiftlint lint --config .swiftlint-ci.yml "$file"
done

- name: Run tests
run: swift test
Expand Down
14 changes: 14 additions & 0 deletions .swiftlint-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
parent_config: .swiftlint.yml

disabled_rules:
- trailing_comma
- todo
- opening_brace
- multiple_closures_with_trailing_closure
- force_cast
- force_try
- shorthand_operator
- cyclomatic_complexity
- function_body_length
- type_body_length
- file_length
23 changes: 23 additions & 0 deletions Sources/Bugbook/App/AppEnvironment.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Foundation

/// Detects whether this is a dev or release build of Bugbook.
enum AppEnvironment {
/// True when running a development build (Xcode Debug / swift build debug).
static var isDev: Bool {
#if DEBUG
return true
#else
// Release builds from the release script use com.bugbook.Bugbook.
// Dev/Xcode builds use com.maxforsey.Bugbook.dev.
let bundleID = Bundle.main.bundleIdentifier ?? ""
return bundleID.hasSuffix(".dev")
#endif
}

/// Human-readable version string, e.g. "0.408 (build 408)".
static var versionString: String {
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "dev"
let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? "0"
return "\(version) (build \(build))"
}
}
16 changes: 16 additions & 0 deletions Sources/Bugbook/App/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ struct MCPServerInfo: Identifiable {
var mcpServers: [MCPServerInfo] = []

var isRecording: Bool = false
var recordingBlockId: UUID?
var flashcardReviewOpen: Bool = false
@ObservationIgnored lazy var aiThreadStore = AiThreadStore()

Expand Down Expand Up @@ -241,6 +242,21 @@ struct MCPServerInfo: Identifiable {
}

private func resolveEntry(for path: String) -> FileEntry {
switch path {
case "bugbook://mail":
return FileEntry(id: path, name: "Mail", path: path, isDirectory: false, kind: .mail, icon: "envelope")
case "bugbook://calendar":
return FileEntry(id: path, name: "Calendar", path: path, isDirectory: false, kind: .calendar, icon: "calendar.badge.clock")
case "bugbook://meetings":
return FileEntry(id: path, name: "Meetings", path: path, isDirectory: false, kind: .meetings, icon: "person.2")
case "bugbook://graph":
return FileEntry(id: path, name: "Graph View", path: path, isDirectory: false, kind: .graphView, icon: "sf:point.3.connected.trianglepath.dotted")
case "bugbook://gateway":
return FileEntry(id: path, name: "Gateway", path: path, isDirectory: false, kind: .gateway, icon: "square.grid.2x2")
default:
break
}

if let row = DatabaseRowNavigationPath.parse(path) {
return FileEntry(
id: path,
Expand Down
27 changes: 27 additions & 0 deletions Sources/Bugbook/App/BugbookApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ struct BugbookApp: App {
WindowGroup {
ContentView()
.tint(Color.fallbackAccent)
.overlay(alignment: .topTrailing) {
if AppEnvironment.isDev {
Text("DEV")
.font(.system(size: 9, weight: .bold, design: .monospaced))
.foregroundStyle(.white)
.padding(.horizontal, 5)
.padding(.vertical, 2)
.background(Color.orange.opacity(0.85))
.clipShape(.capsule)
.padding(.top, 4)
.padding(.trailing, 72)
.allowsHitTesting(false)
}
}
}
.windowStyle(.hiddenTitleBar)
.defaultSize(width: 1100, height: 700)
Expand Down Expand Up @@ -91,11 +105,21 @@ struct BugbookApp: App {
}
.keyboardShortcut("g", modifiers: [.command, .shift])

Button("Mail") {
NotificationCenter.default.post(name: .openMail, object: nil)
}
.keyboardShortcut("m", modifiers: [.command, .shift])

Button("Calendar") {
NotificationCenter.default.post(name: .openCalendar, object: nil)
}
.keyboardShortcut("y", modifiers: [.command, .shift])

Button("Gateway") {
NotificationCenter.default.post(name: .openGateway, object: nil)
}
.keyboardShortcut("0", modifiers: [.command, .shift])

Button("Toggle Theme") {
NotificationCenter.default.post(name: .toggleTheme, object: nil)
}
Expand Down Expand Up @@ -365,15 +389,18 @@ extension Notification.Name {
static let navigateForward = Notification.Name("navigateForward")
static let openDailyNote = Notification.Name("openDailyNote")
static let openGraphView = Notification.Name("openGraphView")
static let openMail = Notification.Name("openMail")
static let editorZoomIn = Notification.Name("editorZoomIn")
static let editorZoomOut = Notification.Name("editorZoomOut")
static let editorZoomReset = Notification.Name("editorZoomReset")
static let openCalendar = Notification.Name("openCalendar")
static let openMeetings = Notification.Name("openMeetings")
static let openGateway = Notification.Name("openGateway")
static let fileDeleted = Notification.Name("fileDeleted")
static let fileMoved = Notification.Name("fileMoved")
static let movePage = Notification.Name("movePage")
static let movePageToDir = Notification.Name("movePageToDir")
static let addToSidebar = Notification.Name("addToSidebar")

// Pane/Workspace system
static let splitPaneRight = Notification.Name("splitPaneRight")
Expand Down
Loading
Loading