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
5 changes: 5 additions & 0 deletions .cursor/environment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "BisonNotes AI (Linux lint & syntax)",
"user": "ubuntu",
"install": "bash .cursor/install.sh"
}
115 changes: 115 additions & 0 deletions .cursor/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env bash
# Cloud Agent install script for BisonNotes AI.
#
# This is a native iOS/watchOS Xcode project that cannot be built or tested on
# Linux (xcodebuild + the iOS Simulator require macOS). On a Linux Cloud Agent
# VM the supported development experience is:
# - SwiftLint (`swiftlint lint`, filtered by SwiftLintBaseline.json)
# - Syntax check (`swiftc -parse <file.swift>`)
#
# Both require a Swift toolchain (SourceKit). This script installs Swiftly, a
# pinned Swift toolchain, and SwiftLint, then wires the required environment
# variables into ~/.bashrc. It is idempotent: re-running it is a no-op once the
# tools are present.
set -euo pipefail

SWIFT_VERSION="6.3.3"
SWIFTLINT_VERSION="0.58.2"
SWIFTLY_HOME_DIR="${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}"
Comment on lines +16 to +18

log() { printf '[cloud-install] %s\n' "$*"; }

# 1. OS dependencies required by the Swift toolchain / SourceKit.
if ! dpkg -s libcurl4-openssl-dev >/dev/null 2>&1; then
log "Installing OS dependencies for Swift..."
sudo apt-get update -qq
sudo apt-get install -y -qq \
binutils gnupg2 libc6-dev libcurl4-openssl-dev libedit2 libgcc-13-dev \
libpython3-dev libstdc++-13-dev libxml2-dev libz3-dev pkg-config tzdata \
unzip zlib1g-dev libncurses-dev
else
log "OS dependencies already present."
fi
Comment on lines +23 to +32

# 2. Swiftly (Swift toolchain manager).
if [ ! -x "$SWIFTLY_HOME_DIR/bin/swiftly" ]; then
log "Installing Swiftly..."
tmp="$(mktemp -d)"
(
cd "$tmp"
curl -fsSL -O "https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz"
tar zxf "swiftly-$(uname -m).tar.gz"
./swiftly init --skip-install --quiet-shell-followup --assume-yes
)
rm -rf "$tmp"
else
log "Swiftly already installed."
fi

# Make swiftly + the active toolchain available to the rest of this script.
# shellcheck disable=SC1091
. "$SWIFTLY_HOME_DIR/env.sh"
hash -r

# 3. Pinned Swift toolchain. Use --global-default so no repo-local
# `.swift-version` file is written into the checkout.
if ! "$SWIFTLY_HOME_DIR/bin/swiftly" list 2>/dev/null | grep -q "Swift $SWIFT_VERSION"; then
log "Installing Swift $SWIFT_VERSION (this downloads ~1 GB)..."
swiftly install "$SWIFT_VERSION" --assume-yes
else
log "Swift $SWIFT_VERSION already installed."
fi
swiftly use --global-default "$SWIFT_VERSION" >/dev/null 2>&1 || true
hash -r

# Location of libsourcekitdInProc.so inside the installed toolchain; SwiftLint
# needs this on Linux.
SOURCEKIT_LIB_DIR="$(dirname "$(ls "$SWIFTLY_HOME_DIR"/toolchains/*/usr/lib/libsourcekitdInProc.so 2>/dev/null | head -n1)")"
export LINUX_SOURCEKIT_LIB_PATH="$SOURCEKIT_LIB_DIR"
Comment on lines +65 to +68

# 4. SwiftLint (Linux binary release).
current_swiftlint=""
if command -v swiftlint >/dev/null 2>&1; then
current_swiftlint="$(swiftlint version 2>/dev/null || true)"
fi
if [ "$current_swiftlint" != "$SWIFTLINT_VERSION" ]; then
log "Installing SwiftLint $SWIFTLINT_VERSION..."
tmp="$(mktemp -d)"
(
cd "$tmp"
curl -fsSL -o swiftlint_linux.zip \
"https://github.com/realm/SwiftLint/releases/download/${SWIFTLINT_VERSION}/swiftlint_linux.zip"
unzip -o -q swiftlint_linux.zip
sudo install -m 0755 swiftlint /usr/local/bin/swiftlint
)
rm -rf "$tmp"
else
log "SwiftLint $SWIFTLINT_VERSION already installed."
fi

# 5. Wire environment variables into ~/.bashrc (idempotent, guarded block).
# ~/.profile already sources ~/.bashrc for bash login shells, so a single
# block here covers both login and interactive Cloud Agent shells.
MARK_BEGIN="# >>> bisonnotes-ai cloud-agent env >>>"
MARK_END="# <<< bisonnotes-ai cloud-agent env <<<"
if ! grep -qF "$MARK_BEGIN" "$HOME/.bashrc" 2>/dev/null; then
log "Adding Swift environment block to ~/.bashrc..."
cat >> "$HOME/.bashrc" <<'EOF'

# >>> bisonnotes-ai cloud-agent env >>>
# Swift toolchain (Swiftly) + SwiftLint SourceKit path for Linux dev.
if [ -f "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh" ]; then
. "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh"
fi
export LINUX_SOURCEKIT_LIB_PATH="$(dirname "$(ls "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}"/toolchains/*/usr/lib/libsourcekitdInProc.so 2>/dev/null | head -n1)")"
# <<< bisonnotes-ai cloud-agent env <<<
EOF
else
log "~/.bashrc already configured."
fi

# 6. Report resulting versions.
log "Swift: $(swift --version 2>/dev/null | head -n1)"
log "SwiftLint: $(swiftlint version 2>/dev/null)"
log "LINUX_SOURCEKIT_LIB_PATH=$LINUX_SOURCEKIT_LIB_PATH"
log "Install complete."
44 changes: 37 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,21 @@ This is a **native iOS/watchOS Xcode project**. It requires **macOS with Xcode 1
- **Code review/editing**: Read, search, and edit all Swift source files, Core Data model XML, plists, entitlements, etc.
- **Git operations**: Full git workflow including branching, committing, and pushing.

### Environment setup (already done by update script)
### Environment setup (Cloud Agent)

- **Swift 6.3.x** installed via [Swiftly](https://swift.org/install/linux/) at `~/.local/share/swiftly/`.
- **SwiftLint 0.58.x** installed at `/usr/local/bin/swiftlint`.
- Environment variables sourced from `~/.bashrc`:
- Swiftly env: `. "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh"`
- SourceKit path: `export LINUX_SOURCEKIT_LIB_PATH=...` (auto-computed from installed toolchain)
The Cloud Agent environment is defined by `.cursor/environment.json`, whose
`install` step runs `.cursor/install.sh`. That script is idempotent and:

- Installs the Swift OS dependencies (libcurl, libpython, etc.).
- Installs **Swift 6.3.3** via [Swiftly](https://swift.org/install/linux/) at `~/.local/share/swiftly/`.
- Installs **SwiftLint 0.58.2** at `/usr/local/bin/swiftlint`.
- Appends a guarded block to `~/.bashrc` (also picked up by login shells because
`~/.profile` sources `~/.bashrc`) that sets:
- Swiftly env: `. "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh"`
- SourceKit path: `export LINUX_SOURCEKIT_LIB_PATH=...` (auto-computed from the installed toolchain)

To change the pinned Swift or SwiftLint version, edit the `SWIFT_VERSION` /
`SWIFTLINT_VERSION` variables at the top of `.cursor/install.sh`.

### Running SwiftLint

Expand All @@ -34,7 +42,29 @@ swiftlint lint # Full lint with all details
swiftlint lint --reporter summary # Summary table only
```

SwiftLint runs with default rules (no `.swiftlint.yml` exists in the repo). The codebase has ~9,000 pre-existing violations (mostly `trailing_whitespace` and `line_length`), so lint errors from these rules are expected and not introduced by agents.
SwiftLint runs with default rules. `BisonNotes AI/BisonNotes AI/.swiftlint.yml`
declares a committed baseline (`SwiftLintBaseline.json`) that is meant to
suppress the ~2,600 pre-existing violations (mostly `line_length` and body/type
length rules) so only newly introduced violations surface.

**Baseline portability caveat:** the committed `SwiftLintBaseline.json` was
generated on macOS and stores absolute file URLs (`file:///Users/champ/...`).
SwiftLint matches baseline entries by file path, so on a Linux checkout (or any
path other than the one it was generated on) the baseline does **not** match and
`swiftlint lint` reports the full ~2,600 pre-existing violations and exits
non-zero. Those violations are pre-existing, not introduced by agents. To get a
clean, baseline-filtered run on Linux, generate a local baseline first and lint
against it:

```bash
cd "BisonNotes AI/BisonNotes AI"
swiftlint lint --write-baseline /tmp/baseline.json # capture current state
swiftlint lint --baseline /tmp/baseline.json # 0 new violations => clean
```

Do not commit a Linux-generated baseline over the macOS one: per-platform rule
behavior can differ slightly, so the maintainer's macOS-generated baseline is
the source of truth for the committed file.

### Running Swift syntax checks

Expand Down