Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
c42a756
chore: open-source setup — CI/CD, SDD, tests, release automation
munterfi Aug 7, 2026
455ebc2
docs: update attribution convention — Generated-by: only, no Co-Autho…
munterfi Aug 7, 2026
6be4024
fix(reachability): replace contentsOfDirectory with statfs to stop TC…
munterfi Aug 7, 2026
3f7596b
feat(ui): modernise all views to macOS-native design standards
munterfi Aug 7, 2026
bd7e248
feat(ui): replace custom icon buttons in Settings with native Form rows
munterfi Aug 7, 2026
16f94d6
fix(ui): restore icon-only row layout in Settings with proper hover
munterfi Aug 7, 2026
82c28cf
fix(ui): reliable animations, drag-to-resize, no main-thread blocking
munterfi Aug 8, 2026
c38807a
feat(ui): add in-app log viewer and one-shot volume speed test
munterfi Aug 8, 2026
f11cf2a
fix(ui): logs button in header, reliable hit areas, consistent hover
munterfi Aug 8, 2026
ef2a37f
fix(perf): honest speed test measurements and robust cleanup
munterfi Aug 8, 2026
705ee42
perf(concurrency): parallelize automount and move blocking work off m…
munterfi Aug 8, 2026
4645639
fix(ui): eliminate button-click delay in VolumeRow with simultaneousG…
munterfi Aug 8, 2026
5f79f55
fix(ui): reduce settings volume buttons to native small control size
munterfi Aug 8, 2026
b6e24ec
fix(ui): replace iconButtonHover ViewModifier with ButtonStyle to fix…
munterfi Aug 8, 2026
65d2a9d
docs(agents): add UI responsiveness rules to AGENTS.md
munterfi Aug 8, 2026
d48071e
fix(concurrency): resolve Swift 6 actor-isolation warnings to zero
munterfi Aug 8, 2026
ace1472
fix(ui): back button always returns to main list, not settings
munterfi Aug 9, 2026
68485f4
fix(ui): use icon hover style for settings volume buttons
munterfi Aug 9, 2026
b9f2646
fix(ui): full-width hover buttons for settings volume actions
munterfi Aug 9, 2026
82eb8bf
fix(automount): restore VolumeManager lifecycle to menu-bar open
munterfi Aug 9, 2026
362737f
refactor(views): migrate from @ObservedObject to @Observable pattern
munterfi Aug 9, 2026
51caae7
fix(mount): replace substring host match with exact extractHost equality
munterfi Aug 9, 2026
ed678aa
fix(services): loop read(2) to completion and log force-unmount result
munterfi Aug 9, 2026
a9c03b0
docs(agents): update AGENTS.md for Observable and AsyncStream migration
munterfi Aug 9, 2026
7680013
fix(automount): restore reliable mounting and logging
munterfi Aug 10, 2026
b8a6b06
refactor: modernize Swift implementation
munterfi Aug 10, 2026
68130dc
fix: keep speed tests and footer responsive
munterfi Aug 10, 2026
755e5b7
docs: streamline story workflow
munterfi Aug 10, 2026
583cc8d
fix: handle mount lifecycle cleanup
munterfi Aug 10, 2026
59f38fc
fix: harden volume lifecycle and imports
munterfi Aug 10, 2026
f0df511
fix: preserve SMB volume identity and lifecycle
munterfi Aug 10, 2026
b723267
fix: validate SMB endpoints
munterfi Aug 10, 2026
20de4bb
feat: improve menu bar workflows
munterfi Aug 10, 2026
a06292e
feat: add repository link and asset sources
munterfi Aug 10, 2026
e677bff
docs: align README logo and assets
munterfi Aug 10, 2026
9f69da8
docs: align README title row
munterfi Aug 10, 2026
ed5ffc2
revert: align README title row
munterfi Aug 10, 2026
dde9985
docs: align README logo visually
munterfi Aug 10, 2026
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
14 changes: 14 additions & 0 deletions .agents/skills/implement-story/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
name: implement-story
description: Implement an approved project story end to end and close its single Markdown record.
argument-hint: Story ID, for example 009
---

# Implement Story

1. Read `AGENTS.md`, `docs/stories/INDEX.md`, and the requested story. Continue only for `OPEN` or `IN_PROGRESS`.
2. Set the story and index to `IN_PROGRESS`.
3. Implement the smallest change that satisfies every acceptance criterion. Keep business logic in services or models and preserve existing changes.
4. After each edit slice, run the cheapest focused format, build, or test check available.
5. Update the story with completed criteria, outcome, tests, and validation. Set it and the index to `CLOSED` only when all criteria are met.
6. Do not commit or push unless explicitly requested; use the story's Conventional Commit type if a commit is requested.
14 changes: 14 additions & 0 deletions .agents/skills/new-story/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
name: new-story
description: Create and register a concise project story for a feature, fix, refactor, test, documentation, or configuration change.
argument-hint: Describe the change
---

# New Story

1. Read `AGENTS.md`, `docs/stories/INDEX.md`, and the relevant existing stories.
2. Confirm the request is not already covered by an `OPEN` or `IN_PROGRESS` story.
3. Choose the next numeric ID and a Conventional Commit type: `feat`, `fix`, `refactor`, `perf`, `docs`, `test`, `chore`, or `ci`.
4. Copy `docs/stories/TEMPLATE.md` to `docs/stories/NNN-short-name.md` and fill it with status `OPEN`, intent, concise acceptance criteria, and validation expectations.
5. Add it to `docs/stories/INDEX.md` in descending numeric order.
6. Do not implement the story until it is approved.
13 changes: 13 additions & 0 deletions .agents/skills/review-codebase/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: review-codebase
description: Perform a read-only codebase review for bugs, risks, spec drift, test gaps, and candidate project stories.
argument-hint: Optional review focus
---

# Review Codebase

1. Inspect the current worktree and branch without modifying files or performing Git operations.
2. Read `AGENTS.md`, `docs/stories/INDEX.md`, and relevant stories.
3. Look for reproducible bugs, security or data risks, contract drift, CI gaps, and meaningful missing tests.
4. Report findings first, ordered by severity, with file and line links. Distinguish evidence from assumptions.
5. Suggest new stories only for work not already covered by an `OPEN` or `IN_PROGRESS` story. Do not create or implement them without approval.
16 changes: 16 additions & 0 deletions .cursorrules
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Cursor rules

Agent guidance for this project lives in a single, provider-neutral source of truth.

Read AGENTS.md at the repository root before making changes. It covers architecture,
build/test/format commands, code style, testing policy, Conventional-Commit + model-attribution
rules, and the Spec-Driven Development workflow.

Highlights:
- Conventional Commits are mandatory; PR titles must be valid Conventional Commits.
- Business logic belongs in Services/ and Models/, never in SwiftUI views.
- Use the Swift Testing framework; keep tests minimal and focused on real business logic.
- Agent commits must include a `Generated-by: <model-id>` trailer (e.g. Generated-by: claude-opus-4-8).
Do NOT add Co-Authored-By: — the human user is the author.
- Never include personal contact information (emails, phone numbers) in any file.
- Do not add third-party dependencies; the app is intentionally dependency-free.
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.{yml,yaml,json,rb}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false
76 changes: 76 additions & 0 deletions .githooks/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/bin/sh
#
# Mounty commit-msg hook:
# 1. Enforce Conventional Commits.
# 2. When Generated-by: is present, validate its format.
# 3. Reject Co-Authored-By: lines that reference AI tools — use Generated-by: instead.
# Install with: ./scripts/install-hooks.sh
#
set -eu

msg_file="$1"

# First non-comment, non-empty line = the subject.
subject=$(grep -vE '^\s*#' "$msg_file" | grep -vE '^\s*$' | head -n1 || true)

# Allow merge/revert/fixup commits through untouched.
case "$subject" in
"Merge "*|"Revert "*|"fixup!"*|"squash!"*) exit 0 ;;
esac

# ── 1. Conventional Commits ───────────────────────────────────────────────────
conventional='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9._/-]+\))?!?: .+'

if ! printf '%s' "$subject" | grep -Eq "$conventional"; then
cat >&2 <<'EOF'
✖ commit-msg: subject is not a valid Conventional Commit.

Expected: <type>[(scope)][!]: <description>
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert

Examples:
feat: add reconnect backoff
fix(mount): treat EEXIST as success
feat!: drop macOS 25 support

See https://www.conventionalcommits.org/
EOF
exit 1
fi

body=$(cat "$msg_file")

# ── 2. Validate Generated-by: format when present ────────────────────────────
if printf '%s' "$body" | grep -qiE '^Generated-by:'; then
# Must be exactly: Generated-by: <non-empty-model-id>
if ! printf '%s' "$body" | grep -qE '^Generated-by: [a-zA-Z0-9._+-]+$'; then
cat >&2 <<'EOF'
✖ commit-msg: malformed Generated-by: trailer.

Expected: Generated-by: <model-id>
Examples: Generated-by: claude-sonnet-4-6
Generated-by: gpt-5
Generated-by: gemini-2.5-pro

The model id must be a single token on the same line, no extra text.
EOF
exit 1
fi
fi

# ── 3. Reject Co-Authored-By: from AI tools ──────────────────────────────────
if printf '%s' "$body" | grep -qiE '^Co-Authored-By:.*\b(Claude|GPT|Copilot|Gemini|Codex|Cursor|OpenAI|Anthropic)\b'; then
cat >&2 <<'EOF'
✖ commit-msg: AI Co-Authored-By: trailer found. Use Generated-by: instead.

The human user is the commit author. Record the model as a tool, not a co-author:

Generated-by: claude-sonnet-4-6

Remove the Co-Authored-By: line and add Generated-by: instead.
See CONTRIBUTING.md for details.
EOF
exit 1
fi

exit 0
29 changes: 29 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/sh
#
# Mounty pre-commit hook: auto-format staged Swift files with swift-format.
# Install with: ./scripts/install-hooks.sh
#
set -eu

# Resolve swift-format (prefer the Xcode toolchain version).
if command -v swift-format >/dev/null 2>&1; then
FORMAT="swift-format"
elif xcrun --find swift-format >/dev/null 2>&1; then
FORMAT="xcrun swift-format"
else
echo "pre-commit: swift-format not found; skipping formatting." >&2
exit 0
fi

# Collect staged Swift files (added/copied/modified).
staged_swift=$(git diff --cached --name-only --diff-filter=ACM -- '*.swift')
[ -z "$staged_swift" ] && exit 0

echo "pre-commit: formatting staged Swift files with swift-format…"
printf '%s\n' "$staged_swift" | while IFS= read -r file; do
[ -f "$file" ] || continue
$FORMAT format -i "$file"
git add "$file"
done

exit 0
34 changes: 34 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Bug report
description: Report a problem with Mounty
labels: ["bug"]
body:
- type: textarea
id: what-happened
attributes:
label: What happened?
description: A clear description of the bug and what you expected instead.
validations:
required: true
- type: textarea
id: repro
attributes:
label: Steps to reproduce
placeholder: |
1. Add a volume smb://...
2. Enable automount
3. Toggle VPN
validations:
required: true
- type: input
id: versions
attributes:
label: Mounty & macOS version
placeholder: "Mounty 1.1.0, macOS 26.1"
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant logs
description: "Console.app logs filtered by subsystem `ch.maptic.Mounty` (or `Mounty`)."
render: shell
21 changes: 21 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Feature request
description: Suggest an idea for Mounty
labels: ["enhancement"]
body:
- type: textarea
id: problem
attributes:
label: Problem
description: What problem would this feature solve? What are you trying to do?
validations:
required: true
- type: textarea
id: proposal
attributes:
label: Proposed solution
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
22 changes: 22 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!--
The PR title MUST be a valid Conventional Commit (e.g. "feat: add reconnect backoff").
It becomes the squash-merge commit and drives the automated release.
-->

## What & why

<!-- Describe the change and the motivation. Link the story in docs/stories/ if applicable. -->

## Type of change

- [ ] `fix` — bug fix (patch release)
- [ ] `feat` — new feature (minor release)
- [ ] breaking change (`!` / `BREAKING CHANGE:` — major release)
- [ ] `docs` / `chore` / `refactor` / `test` / `ci` (no release)

## Checklist

- [ ] PR title is a valid Conventional Commit
- [ ] Code is formatted (`swift-format`) and CI is green
- [ ] Business logic changes are covered by tests
- [ ] If AI-assisted, commits include a `Generated-by: <model-id>` trailer
17 changes: 17 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# GitHub Copilot instructions

This project's agent guidance is maintained in a single, provider-neutral source of truth.

👉 **Read [`AGENTS.md`](../AGENTS.md)** at the repository root. It covers the architecture,
build/test/format commands, code style, testing policy, Conventional-Commit + model-attribution
rules, and the Spec-Driven Development workflow.

Key reminders for generated code and commits:

- Follow **Conventional Commits**; PR titles must be valid Conventional Commits.
- Business logic goes in `Services/`/`Models/`, not in SwiftUI views.
- Use the **Swift Testing** framework for tests; keep them minimal and meaningful.
- Agent commits must include a `Generated-by: <model-id>` trailer (e.g. `Generated-by: gpt-5`).
Do **not** add `Co-Authored-By:` — the human user is the author.
- Never include personal contact information (emails, phone numbers) in any file. Use only the
GitHub advisory URL for security reporting.
59 changes: 59 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: CI

on:
push:
branches: [main]
pull_request:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
# Ensure the PR title is a valid Conventional Commit (it becomes the squash commit
# that drives release-please).
pr-title:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
pull-requests: read
steps:
- uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

format:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Select Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: swift-format lint
run: xcrun swift-format lint --strict --recursive Mounty MountyTests

build-test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Select Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: Show toolchain
run: xcodebuild -version && swift --version
- name: Build & test
run: |
xcodebuild \
-project Mounty.xcodeproj \
-scheme Mounty \
-configuration Debug \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO \
SWIFT_TREAT_WARNINGS_AS_ERRORS=YES \
GCC_TREAT_WARNINGS_AS_ERRORS=YES \
clean test
Loading
Loading