opencode-skills-antigravity 1.0.13 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-skills/app-store-changelog/SKILL.md +75 -0
- package/bundled-skills/app-store-changelog/agents/openai.yaml +4 -0
- package/bundled-skills/app-store-changelog/references/release-notes-guidelines.md +34 -0
- package/bundled-skills/app-store-changelog/scripts/collect_release_changes.sh +33 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +14 -14
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/sources/sources.md +10 -0
- package/bundled-skills/docs/users/bundles.md +9 -1
- package/bundled-skills/docs/users/claude-code-skills.md +5 -1
- package/bundled-skills/docs/users/codex-cli-skills.md +8 -0
- package/bundled-skills/docs/users/cursor-skills.md +4 -0
- package/bundled-skills/docs/users/faq.md +45 -0
- package/bundled-skills/docs/users/gemini-cli-skills.md +5 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/skills-vs-mcp-tools.md +89 -0
- package/bundled-skills/docs/users/usage.md +14 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/github/SKILL.md +76 -0
- package/bundled-skills/github/agents/openai.yaml +4 -0
- package/bundled-skills/ios-debugger-agent/SKILL.md +59 -0
- package/bundled-skills/ios-debugger-agent/agents/openai.yaml +4 -0
- package/bundled-skills/macos-menubar-tuist-app/SKILL.md +109 -0
- package/bundled-skills/macos-menubar-tuist-app/agents/openai.yaml +4 -0
- package/bundled-skills/macos-spm-app-packaging/SKILL.md +105 -0
- package/bundled-skills/macos-spm-app-packaging/agents/openai.yaml +4 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/bootstrap/Package.swift +17 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/Resources/.keep +0 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/main.swift +11 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/bootstrap/version.env +2 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/build_icon.sh +49 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/compile_and_run.sh +63 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/launch.sh +28 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/make_appcast.sh +82 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/package_app.sh +206 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/setup_dev_signing.sh +52 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/sign-and-notarize.sh +52 -0
- package/bundled-skills/macos-spm-app-packaging/assets/templates/version.env +2 -0
- package/bundled-skills/macos-spm-app-packaging/references/packaging.md +17 -0
- package/bundled-skills/macos-spm-app-packaging/references/release.md +32 -0
- package/bundled-skills/macos-spm-app-packaging/references/scaffold.md +79 -0
- package/bundled-skills/orchestrate-batch-refactor/SKILL.md +97 -0
- package/bundled-skills/orchestrate-batch-refactor/agents/openai.yaml +4 -0
- package/bundled-skills/orchestrate-batch-refactor/references/agent-prompt-templates.md +53 -0
- package/bundled-skills/orchestrate-batch-refactor/references/work-packet-template.md +31 -0
- package/bundled-skills/project-skill-audit/SKILL.md +190 -0
- package/bundled-skills/project-skill-audit/agents/openai.yaml +4 -0
- package/bundled-skills/react-component-performance/SKILL.md +135 -0
- package/bundled-skills/react-component-performance/agents/openai.yaml +4 -0
- package/bundled-skills/react-component-performance/references/examples.md +88 -0
- package/bundled-skills/simplify-code/SKILL.md +179 -0
- package/bundled-skills/snowflake-development/SKILL.md +5 -0
- package/bundled-skills/swift-concurrency-expert/SKILL.md +113 -0
- package/bundled-skills/swift-concurrency-expert/agents/openai.yaml +4 -0
- package/bundled-skills/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
- package/bundled-skills/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
- package/bundled-skills/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
- package/bundled-skills/swiftui-liquid-glass/SKILL.md +98 -0
- package/bundled-skills/swiftui-liquid-glass/agents/openai.yaml +4 -0
- package/bundled-skills/swiftui-liquid-glass/references/liquid-glass.md +280 -0
- package/bundled-skills/swiftui-performance-audit/SKILL.md +114 -0
- package/bundled-skills/swiftui-performance-audit/agents/openai.yaml +4 -0
- package/bundled-skills/swiftui-performance-audit/references/code-smells.md +150 -0
- package/bundled-skills/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
- package/bundled-skills/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
- package/bundled-skills/swiftui-performance-audit/references/profiling-intake.md +44 -0
- package/bundled-skills/swiftui-performance-audit/references/report-template.md +47 -0
- package/bundled-skills/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
- package/bundled-skills/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
- package/bundled-skills/swiftui-ui-patterns/SKILL.md +103 -0
- package/bundled-skills/swiftui-ui-patterns/agents/openai.yaml +4 -0
- package/bundled-skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
- package/bundled-skills/swiftui-ui-patterns/references/async-state.md +96 -0
- package/bundled-skills/swiftui-ui-patterns/references/components-index.md +50 -0
- package/bundled-skills/swiftui-ui-patterns/references/controls.md +57 -0
- package/bundled-skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
- package/bundled-skills/swiftui-ui-patterns/references/focus.md +90 -0
- package/bundled-skills/swiftui-ui-patterns/references/form.md +97 -0
- package/bundled-skills/swiftui-ui-patterns/references/grids.md +71 -0
- package/bundled-skills/swiftui-ui-patterns/references/haptics.md +71 -0
- package/bundled-skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
- package/bundled-skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
- package/bundled-skills/swiftui-ui-patterns/references/list.md +86 -0
- package/bundled-skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
- package/bundled-skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
- package/bundled-skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
- package/bundled-skills/swiftui-ui-patterns/references/media.md +73 -0
- package/bundled-skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
- package/bundled-skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
- package/bundled-skills/swiftui-ui-patterns/references/overlay.md +45 -0
- package/bundled-skills/swiftui-ui-patterns/references/performance.md +62 -0
- package/bundled-skills/swiftui-ui-patterns/references/previews.md +48 -0
- package/bundled-skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
- package/bundled-skills/swiftui-ui-patterns/references/scrollview.md +87 -0
- package/bundled-skills/swiftui-ui-patterns/references/searchable.md +71 -0
- package/bundled-skills/swiftui-ui-patterns/references/sheets.md +155 -0
- package/bundled-skills/swiftui-ui-patterns/references/split-views.md +72 -0
- package/bundled-skills/swiftui-ui-patterns/references/tabview.md +114 -0
- package/bundled-skills/swiftui-ui-patterns/references/theming.md +71 -0
- package/bundled-skills/swiftui-ui-patterns/references/title-menus.md +93 -0
- package/bundled-skills/swiftui-ui-patterns/references/top-bar.md +49 -0
- package/bundled-skills/swiftui-view-refactor/SKILL.md +210 -0
- package/bundled-skills/swiftui-view-refactor/agents/openai.yaml +4 -0
- package/bundled-skills/swiftui-view-refactor/references/mv-patterns.md +161 -0
- package/package.json +1 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github
|
|
3
|
+
description: "Use the `gh` CLI for issues, pull requests, Actions runs, and GitHub API queries."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: "Dimillian/Skills (MIT)"
|
|
6
|
+
date_added: "2026-03-25"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# GitHub Skill
|
|
10
|
+
|
|
11
|
+
Use the `gh` CLI to interact with GitHub. Always specify `--repo owner/repo` when not in a git directory, or use URLs directly.
|
|
12
|
+
|
|
13
|
+
## When to Use
|
|
14
|
+
|
|
15
|
+
- When the user asks about GitHub issues, pull requests, workflow runs, or CI failures.
|
|
16
|
+
- When you need `gh issue`, `gh pr`, `gh run`, or `gh api` from the command line.
|
|
17
|
+
|
|
18
|
+
## Pull Requests
|
|
19
|
+
|
|
20
|
+
Check CI status on a PR:
|
|
21
|
+
```bash
|
|
22
|
+
gh pr checks 55 --repo owner/repo
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
List recent workflow runs:
|
|
26
|
+
```bash
|
|
27
|
+
gh run list --repo owner/repo --limit 10
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
View a run and see which steps failed:
|
|
31
|
+
```bash
|
|
32
|
+
gh run view <run-id> --repo owner/repo
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
View logs for failed steps only:
|
|
36
|
+
```bash
|
|
37
|
+
gh run view <run-id> --repo owner/repo --log-failed
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Debugging a CI Failure
|
|
41
|
+
|
|
42
|
+
Follow this sequence to investigate a failing CI run:
|
|
43
|
+
|
|
44
|
+
1. **Check PR status** — identify which checks are failing:
|
|
45
|
+
```bash
|
|
46
|
+
gh pr checks 55 --repo owner/repo
|
|
47
|
+
```
|
|
48
|
+
2. **List recent runs** — find the relevant run ID:
|
|
49
|
+
```bash
|
|
50
|
+
gh run list --repo owner/repo --limit 10
|
|
51
|
+
```
|
|
52
|
+
3. **View the failed run** — see which jobs and steps failed:
|
|
53
|
+
```bash
|
|
54
|
+
gh run view <run-id> --repo owner/repo
|
|
55
|
+
```
|
|
56
|
+
4. **Fetch failure logs** — get the detailed output for failed steps:
|
|
57
|
+
```bash
|
|
58
|
+
gh run view <run-id> --repo owner/repo --log-failed
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## API for Advanced Queries
|
|
62
|
+
|
|
63
|
+
The `gh api` command is useful for accessing data not available through other subcommands.
|
|
64
|
+
|
|
65
|
+
Get PR with specific fields:
|
|
66
|
+
```bash
|
|
67
|
+
gh api repos/owner/repo/pulls/55 --jq '.title, .state, .user.login'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## JSON Output
|
|
71
|
+
|
|
72
|
+
Most commands support `--json` for structured output. You can use `--jq` to filter:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
gh issue list --repo owner/repo --json number,title --jq '.[] | "\(.number): \(.title)"'
|
|
76
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ios-debugger-agent
|
|
3
|
+
description: Debug the current iOS project on a booted simulator with XcodeBuildMCP.
|
|
4
|
+
risk: safe
|
|
5
|
+
source: "Dimillian/Skills (MIT)"
|
|
6
|
+
date_added: "2026-03-25"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# iOS Debugger Agent
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
Use XcodeBuildMCP to build and run the current project scheme on a booted iOS simulator, interact with the UI, and capture logs. Prefer the MCP tools for simulator control, logs, and view inspection.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- When the user asks to run, debug, or inspect an iOS app on a simulator.
|
|
17
|
+
- When you need simulator UI interaction, screenshots, or runtime logs via XcodeBuildMCP.
|
|
18
|
+
|
|
19
|
+
## Core Workflow
|
|
20
|
+
Follow this sequence unless the user asks for a narrower action.
|
|
21
|
+
|
|
22
|
+
### 1) Discover the booted simulator
|
|
23
|
+
- Call `mcp__XcodeBuildMCP__list_sims` and select the simulator with state `Booted`.
|
|
24
|
+
- If none are booted, ask the user to boot one (do not boot automatically unless asked).
|
|
25
|
+
|
|
26
|
+
### 2) Set session defaults
|
|
27
|
+
- Call `mcp__XcodeBuildMCP__session-set-defaults` with:
|
|
28
|
+
- `projectPath` or `workspacePath` (whichever the repo uses)
|
|
29
|
+
- `scheme` for the current app
|
|
30
|
+
- `simulatorId` from the booted device
|
|
31
|
+
- Optional: `configuration: "Debug"`, `useLatestOS: true`
|
|
32
|
+
|
|
33
|
+
### 3) Build + run (when requested)
|
|
34
|
+
- Call `mcp__XcodeBuildMCP__build_run_sim`.
|
|
35
|
+
- **If the build fails**, check the error output and retry (optionally with `preferXcodebuild: true`) or escalate to the user before attempting any UI interaction.
|
|
36
|
+
- **After a successful build**, verify the app launched by calling `mcp__XcodeBuildMCP__describe_ui` or `mcp__XcodeBuildMCP__screenshot` before proceeding to UI interaction.
|
|
37
|
+
- If the app is already built and only launch is requested, use `mcp__XcodeBuildMCP__launch_app_sim`.
|
|
38
|
+
- If bundle id is unknown:
|
|
39
|
+
1) `mcp__XcodeBuildMCP__get_sim_app_path`
|
|
40
|
+
2) `mcp__XcodeBuildMCP__get_app_bundle_id`
|
|
41
|
+
|
|
42
|
+
## UI Interaction & Debugging
|
|
43
|
+
Use these when asked to inspect or interact with the running app.
|
|
44
|
+
|
|
45
|
+
- **Describe UI**: `mcp__XcodeBuildMCP__describe_ui` before tapping or swiping.
|
|
46
|
+
- **Tap**: `mcp__XcodeBuildMCP__tap` (prefer `id` or `label`; use coordinates only if needed).
|
|
47
|
+
- **Type**: `mcp__XcodeBuildMCP__type_text` after focusing a field.
|
|
48
|
+
- **Gestures**: `mcp__XcodeBuildMCP__gesture` for common scrolls and edge swipes.
|
|
49
|
+
- **Screenshot**: `mcp__XcodeBuildMCP__screenshot` for visual confirmation.
|
|
50
|
+
|
|
51
|
+
## Logs & Console Output
|
|
52
|
+
- Start logs: `mcp__XcodeBuildMCP__start_sim_log_cap` with the app bundle id.
|
|
53
|
+
- Stop logs: `mcp__XcodeBuildMCP__stop_sim_log_cap` and summarize important lines.
|
|
54
|
+
- For console output, set `captureConsole: true` and relaunch if required.
|
|
55
|
+
|
|
56
|
+
## Troubleshooting
|
|
57
|
+
- If build fails, ask whether to retry with `preferXcodebuild: true`.
|
|
58
|
+
- If the wrong app launches, confirm the scheme and bundle id.
|
|
59
|
+
- If UI elements are not hittable, re-run `describe_ui` after layout changes.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: macos-menubar-tuist-app
|
|
3
|
+
description: Build, refactor, or review SwiftUI macOS menubar apps that use Tuist.
|
|
4
|
+
risk: safe
|
|
5
|
+
source: "Dimillian/Skills (MIT)"
|
|
6
|
+
date_added: "2026-03-25"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# macos-menubar-tuist-app
|
|
10
|
+
|
|
11
|
+
Build and maintain macOS menubar apps with a Tuist-first workflow and stable launch scripts. Preserve strict architecture boundaries so networking, state, and UI remain testable and predictable.
|
|
12
|
+
|
|
13
|
+
## When to Use
|
|
14
|
+
|
|
15
|
+
- When working on LSUIElement menubar utilities built with Tuist and SwiftUI.
|
|
16
|
+
- When you need Tuist manifests, launch scripts, or architecture guidance for a menubar app.
|
|
17
|
+
|
|
18
|
+
## Core Rules
|
|
19
|
+
|
|
20
|
+
- Keep the app menubar-only unless explicitly told otherwise. Use `LSUIElement = true` by default.
|
|
21
|
+
- Keep transport and decoding logic outside views. Do not call networking from SwiftUI view bodies.
|
|
22
|
+
- Keep state transitions in a store layer (`@Observable` or equivalent), not in row/view presentation code.
|
|
23
|
+
- Keep model decoding resilient to API drift: optional fields, safe fallbacks, and defensive parsing.
|
|
24
|
+
- Treat Tuist manifests as the source of truth. Do not rely on hand-edited generated Xcode artifacts.
|
|
25
|
+
- Prefer script-based launch for local iteration when `tuist run` is unreliable for macOS target/device resolution.
|
|
26
|
+
- Prefer `tuist xcodebuild build` over raw `xcodebuild` in local run scripts when building generated projects.
|
|
27
|
+
|
|
28
|
+
## Expected File Shape
|
|
29
|
+
|
|
30
|
+
Use this placement by default:
|
|
31
|
+
|
|
32
|
+
- `Project.swift`: app target, settings, resources, `Info.plist` keys
|
|
33
|
+
- `Sources/*Model*.swift`: API/domain models and decoding
|
|
34
|
+
- `Sources/*Client*.swift`: requests, response mapping, transport concerns
|
|
35
|
+
- `Sources/*Store*.swift`: observable state, refresh policy, filtering, caching
|
|
36
|
+
- `Sources/*Menu*View*.swift`: menu composition and top-level UI state
|
|
37
|
+
- `Sources/*Row*View*.swift`: row rendering and lightweight interactions
|
|
38
|
+
- `run-menubar.sh`: canonical local restart/build/launch path
|
|
39
|
+
- `stop-menubar.sh`: explicit stop helper when needed
|
|
40
|
+
|
|
41
|
+
## Workflow
|
|
42
|
+
|
|
43
|
+
1. Confirm Tuist ownership
|
|
44
|
+
- Verify `Tuist.swift` and `Project.swift` (or workspace manifests) exist.
|
|
45
|
+
- Read existing run scripts before changing launch behavior.
|
|
46
|
+
|
|
47
|
+
2. Probe backend behavior before coding assumptions
|
|
48
|
+
- Use `curl` to verify endpoint shape, auth requirements, and pagination behavior.
|
|
49
|
+
- If endpoint ignores `limit/page`, implement full-list handling with local trimming in the store.
|
|
50
|
+
|
|
51
|
+
3. Implement layers from bottom to top
|
|
52
|
+
- Define/adjust models first.
|
|
53
|
+
- Add or update client request/decoding logic.
|
|
54
|
+
- Update store refresh, filtering, and cache policy.
|
|
55
|
+
- Wire views last.
|
|
56
|
+
|
|
57
|
+
4. Keep app wiring minimal
|
|
58
|
+
- Keep app entry focused on scene/menu wiring and dependency injection.
|
|
59
|
+
- Avoid embedding business logic in `App` or menu scene declarations.
|
|
60
|
+
|
|
61
|
+
5. Standardize launch ergonomics
|
|
62
|
+
- Ensure run script restarts an existing instance before relaunching.
|
|
63
|
+
- Ensure run script does not open Xcode as a side effect.
|
|
64
|
+
- Use `tuist generate --no-open` when generation is required.
|
|
65
|
+
- When the run script builds the generated project, prefer `TUIST_SKIP_UPDATE_CHECK=1 tuist xcodebuild build ...` instead of invoking raw `xcodebuild` directly.
|
|
66
|
+
|
|
67
|
+
## Validation Matrix
|
|
68
|
+
|
|
69
|
+
Run validations after edits:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
TUIST_SKIP_UPDATE_CHECK=1 tuist xcodebuild build -scheme <TargetName> -configuration Debug
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If launch workflow changed:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
./run-menubar.sh
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
If shell scripts changed:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
bash -n run-menubar.sh
|
|
85
|
+
bash -n stop-menubar.sh
|
|
86
|
+
./run-menubar.sh
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Failure Patterns and Fix Direction
|
|
90
|
+
|
|
91
|
+
- `tuist run` cannot resolve the macOS destination:
|
|
92
|
+
Use run/stop scripts as canonical local run path.
|
|
93
|
+
|
|
94
|
+
- Menu UI is laggy or inconsistent after refresh:
|
|
95
|
+
Move derived state and filtering into the store; keep views render-only.
|
|
96
|
+
|
|
97
|
+
- API payload changes break decode:
|
|
98
|
+
Relax model decoding with optional fields and defaults, then surface missing data safely in UI.
|
|
99
|
+
|
|
100
|
+
- Feature asks for quick UI patch:
|
|
101
|
+
Trace root cause in model/client/store before changing row/menu presentation.
|
|
102
|
+
|
|
103
|
+
## Completion Checklist
|
|
104
|
+
|
|
105
|
+
- Preserve menubar-only behavior unless explicitly changed.
|
|
106
|
+
- Keep network and state logic out of SwiftUI view bodies.
|
|
107
|
+
- Keep Tuist manifests and run scripts aligned with actual build/run flow.
|
|
108
|
+
- Run the validation matrix for touched areas.
|
|
109
|
+
- Report concrete commands run and outcomes.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "macOS Menubar Tuist App"
|
|
3
|
+
short_description: "Tuist-first macOS menubar app build and maintenance"
|
|
4
|
+
default_prompt: "Use $macos-menubar-tuist-app to scaffold or refactor a menubar-only macOS app with Tuist, layered state architecture, and script-based run validation."
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: macos-spm-app-packaging
|
|
3
|
+
description: Scaffold, build, sign, and package SwiftPM macOS apps without Xcode projects.
|
|
4
|
+
risk: safe
|
|
5
|
+
source: "Dimillian/Skills (MIT)"
|
|
6
|
+
date_added: "2026-03-25"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# macOS SwiftPM App Packaging (No Xcode)
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
Bootstrap a complete SwiftPM macOS app folder, then build, package, and run it without Xcode. Use `assets/templates/bootstrap/` for the starter layout and `references/packaging.md` + `references/release.md` for packaging and release details.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- When the user needs a SwiftPM-based macOS app without relying on an Xcode project.
|
|
17
|
+
- When you need packaging, signing, notarization, or appcast guidance for a SwiftPM app.
|
|
18
|
+
|
|
19
|
+
## Two-Step Workflow
|
|
20
|
+
1) Bootstrap the project folder
|
|
21
|
+
- Copy `assets/templates/bootstrap/` into a new repo.
|
|
22
|
+
- Rename `MyApp` in `Package.swift`, `Sources/MyApp/`, and `version.env`.
|
|
23
|
+
- Customize `APP_NAME`, `BUNDLE_ID`, and versions.
|
|
24
|
+
|
|
25
|
+
2) Build, package, and run the bootstrapped app
|
|
26
|
+
- Copy scripts from `assets/templates/` into your repo (for example, `Scripts/`).
|
|
27
|
+
- Build/tests: `swift build` and `swift test`.
|
|
28
|
+
- Package: `Scripts/package_app.sh`.
|
|
29
|
+
- Run: `Scripts/compile_and_run.sh` (preferred) or `Scripts/launch.sh`.
|
|
30
|
+
- Release (optional): `Scripts/sign-and-notarize.sh` and `Scripts/make_appcast.sh`.
|
|
31
|
+
- Tag + GitHub release (optional): create a git tag, upload the zip/appcast to the GitHub release, and publish.
|
|
32
|
+
|
|
33
|
+
## Minimum End-to-End Example
|
|
34
|
+
Shortest path from bootstrap to a running app:
|
|
35
|
+
```bash
|
|
36
|
+
# 1. Copy and rename the skeleton
|
|
37
|
+
cp -R assets/templates/bootstrap/ ~/Projects/MyApp
|
|
38
|
+
cd ~/Projects/MyApp
|
|
39
|
+
sed -i '' 's/MyApp/HelloApp/g' Package.swift version.env
|
|
40
|
+
|
|
41
|
+
# 2. Copy scripts
|
|
42
|
+
cp assets/templates/package_app.sh Scripts/
|
|
43
|
+
cp assets/templates/compile_and_run.sh Scripts/
|
|
44
|
+
chmod +x Scripts/*.sh
|
|
45
|
+
|
|
46
|
+
# 3. Build and launch
|
|
47
|
+
swift build
|
|
48
|
+
Scripts/compile_and_run.sh
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Validation Checkpoints
|
|
52
|
+
Run these after key steps to catch failures early before proceeding to the next stage.
|
|
53
|
+
|
|
54
|
+
**After packaging (`Scripts/package_app.sh`):**
|
|
55
|
+
```bash
|
|
56
|
+
# Confirm .app bundle structure is intact
|
|
57
|
+
ls -R build/HelloApp.app/Contents
|
|
58
|
+
|
|
59
|
+
# Check that the binary is present and executable
|
|
60
|
+
file build/HelloApp.app/Contents/MacOS/HelloApp
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**After signing (`Scripts/sign-and-notarize.sh` or ad-hoc dev signing):**
|
|
64
|
+
```bash
|
|
65
|
+
# Inspect signature and entitlements
|
|
66
|
+
codesign -dv --verbose=4 build/HelloApp.app
|
|
67
|
+
|
|
68
|
+
# Verify the bundle passes Gatekeeper checks locally
|
|
69
|
+
spctl --assess --type execute --verbose build/HelloApp.app
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**After notarization and stapling:**
|
|
73
|
+
```bash
|
|
74
|
+
# Confirm the staple ticket is attached
|
|
75
|
+
stapler validate build/HelloApp.app
|
|
76
|
+
|
|
77
|
+
# Re-run Gatekeeper to confirm notarization is recognised
|
|
78
|
+
spctl --assess --type execute --verbose build/HelloApp.app
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Common Notarization Failures
|
|
82
|
+
| Symptom | Likely Cause | Recovery |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `The software asset has already been uploaded` | Duplicate submission for same version | Bump `BUILD_NUMBER` in `version.env` and repackage. |
|
|
85
|
+
| `Package Invalid: Invalid Code Signing Entitlements` | Entitlements in `.entitlements` file don't match provisioning | Audit entitlements against Apple's allowed set; remove unsupported keys. |
|
|
86
|
+
| `The executable does not have the hardened runtime enabled` | Missing `--options runtime` flag in `codesign` invocation | Edit `sign-and-notarize.sh` to add `--options runtime` to all `codesign` calls. |
|
|
87
|
+
| Notarization hangs / no status email | `xcrun notarytool` network or credential issue | Run `xcrun notarytool history` to check status; re-export App Store Connect API key if expired. |
|
|
88
|
+
| `stapler validate` fails after successful notarization | Ticket not yet propagated | Wait ~60 s, then re-run `xcrun stapler staple`. |
|
|
89
|
+
|
|
90
|
+
## Templates
|
|
91
|
+
- `assets/templates/package_app.sh`: Build binaries, create the .app bundle, copy resources, sign.
|
|
92
|
+
- `assets/templates/compile_and_run.sh`: Dev loop to kill running app, package, launch.
|
|
93
|
+
- `assets/templates/build_icon.sh`: Generate .icns from an Icon Composer file (requires Xcode install).
|
|
94
|
+
- `assets/templates/sign-and-notarize.sh`: Notarize, staple, and zip a release build.
|
|
95
|
+
- `assets/templates/make_appcast.sh`: Generate Sparkle appcast entries for updates.
|
|
96
|
+
- `assets/templates/setup_dev_signing.sh`: Create a stable dev code-signing identity.
|
|
97
|
+
- `assets/templates/launch.sh`: Simple launcher for a packaged .app.
|
|
98
|
+
- `assets/templates/version.env`: Example version file consumed by packaging scripts.
|
|
99
|
+
- `assets/templates/bootstrap/`: Minimal SwiftPM macOS app skeleton (Package.swift, Sources/, version.env).
|
|
100
|
+
|
|
101
|
+
## Notes
|
|
102
|
+
- Keep entitlements and signing configuration explicit; edit the template scripts instead of reimplementing.
|
|
103
|
+
- Remove Sparkle steps if you do not use Sparkle for updates.
|
|
104
|
+
- Sparkle relies on the bundle build number (`CFBundleVersion`), so `BUILD_NUMBER` in `version.env` must increase for each update.
|
|
105
|
+
- For menu bar apps, set `MENU_BAR_APP=1` when packaging to emit `LSUIElement` in Info.plist.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// swift-tools-version: 6.2
|
|
2
|
+
import PackageDescription
|
|
3
|
+
|
|
4
|
+
let package = Package(
|
|
5
|
+
name: "MyApp",
|
|
6
|
+
platforms: [
|
|
7
|
+
.macOS(.v14),
|
|
8
|
+
],
|
|
9
|
+
targets: [
|
|
10
|
+
.executableTarget(
|
|
11
|
+
name: "MyApp",
|
|
12
|
+
path: "Sources/MyApp",
|
|
13
|
+
resources: [
|
|
14
|
+
.process("Resources"),
|
|
15
|
+
])
|
|
16
|
+
]
|
|
17
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ICON_FILE=${1:-Icon.icon}
|
|
5
|
+
BASENAME=${2:-Icon}
|
|
6
|
+
OUT_ROOT=${3:-build/icon}
|
|
7
|
+
XCODE_APP=${XCODE_APP:-/Applications/Xcode.app}
|
|
8
|
+
|
|
9
|
+
ICTOOL="$XCODE_APP/Contents/Applications/Icon Composer.app/Contents/Executables/ictool"
|
|
10
|
+
if [[ ! -x "$ICTOOL" ]]; then
|
|
11
|
+
ICTOOL="$XCODE_APP/Contents/Applications/Icon Composer.app/Contents/Executables/icontool"
|
|
12
|
+
fi
|
|
13
|
+
if [[ ! -x "$ICTOOL" ]]; then
|
|
14
|
+
echo "ictool/icontool not found. Set XCODE_APP if Xcode is elsewhere." >&2
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
ICONSET_DIR="$OUT_ROOT/${BASENAME}.iconset"
|
|
19
|
+
TMP_DIR="$OUT_ROOT/tmp"
|
|
20
|
+
mkdir -p "$ICONSET_DIR" "$TMP_DIR"
|
|
21
|
+
|
|
22
|
+
MASTER_ART="$TMP_DIR/icon_art_824.png"
|
|
23
|
+
MASTER_1024="$TMP_DIR/icon_1024.png"
|
|
24
|
+
|
|
25
|
+
# Render inner art (no margin) with macOS Default appearance.
|
|
26
|
+
"$ICTOOL" "$ICON_FILE" \
|
|
27
|
+
--export-preview macOS Default 824 824 1 -45 "$MASTER_ART"
|
|
28
|
+
|
|
29
|
+
# Pad to 1024x1024 with transparent border.
|
|
30
|
+
sips --padToHeightWidth 1024 1024 "$MASTER_ART" --out "$MASTER_1024" >/dev/null
|
|
31
|
+
|
|
32
|
+
# Generate required sizes.
|
|
33
|
+
sizes=(16 32 64 128 256 512 1024)
|
|
34
|
+
for sz in "${sizes[@]}"; do
|
|
35
|
+
out="$ICONSET_DIR/icon_${sz}x${sz}.png"
|
|
36
|
+
sips -z "$sz" "$sz" "$MASTER_1024" --out "$out" >/dev/null
|
|
37
|
+
if [[ "$sz" -ne 1024 ]]; then
|
|
38
|
+
dbl=$((sz*2))
|
|
39
|
+
out2="$ICONSET_DIR/icon_${sz}x${sz}@2x.png"
|
|
40
|
+
sips -z "$dbl" "$dbl" "$MASTER_1024" --out "$out2" >/dev/null
|
|
41
|
+
fi
|
|
42
|
+
done
|
|
43
|
+
|
|
44
|
+
# 512x512@2x already covered by 1024; ensure it exists.
|
|
45
|
+
cp "$MASTER_1024" "$ICONSET_DIR/icon_512x512@2x.png"
|
|
46
|
+
|
|
47
|
+
iconutil -c icns "$ICONSET_DIR" -o Icon.icns
|
|
48
|
+
|
|
49
|
+
echo "Icon.icns generated at $(pwd)/Icon.icns"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Kill running instances, package, relaunch, verify.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
6
|
+
APP_NAME=${APP_NAME:-MyApp}
|
|
7
|
+
APP_BUNDLE="${ROOT_DIR}/${APP_NAME}.app"
|
|
8
|
+
APP_PROCESS_PATTERN="${APP_NAME}.app/Contents/MacOS/${APP_NAME}"
|
|
9
|
+
DEBUG_PROCESS_PATTERN="${ROOT_DIR}/.build/debug/${APP_NAME}"
|
|
10
|
+
RELEASE_PROCESS_PATTERN="${ROOT_DIR}/.build/release/${APP_NAME}"
|
|
11
|
+
RUN_TESTS=0
|
|
12
|
+
RELEASE_ARCHES=""
|
|
13
|
+
|
|
14
|
+
log() { printf '%s\n' "$*"; }
|
|
15
|
+
fail() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
|
|
16
|
+
|
|
17
|
+
for arg in "$@"; do
|
|
18
|
+
case "${arg}" in
|
|
19
|
+
--test|-t) RUN_TESTS=1 ;;
|
|
20
|
+
--release-universal) RELEASE_ARCHES="arm64 x86_64" ;;
|
|
21
|
+
--release-arches=*) RELEASE_ARCHES="${arg#*=}" ;;
|
|
22
|
+
--help|-h)
|
|
23
|
+
log "Usage: $(basename "$0") [--test] [--release-universal] [--release-arches=\"arm64 x86_64\"]"
|
|
24
|
+
exit 0
|
|
25
|
+
;;
|
|
26
|
+
esac
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
log "==> Killing existing ${APP_NAME} instances"
|
|
30
|
+
pkill -f "${APP_PROCESS_PATTERN}" 2>/dev/null || true
|
|
31
|
+
pkill -f "${DEBUG_PROCESS_PATTERN}" 2>/dev/null || true
|
|
32
|
+
pkill -f "${RELEASE_PROCESS_PATTERN}" 2>/dev/null || true
|
|
33
|
+
pkill -x "${APP_NAME}" 2>/dev/null || true
|
|
34
|
+
|
|
35
|
+
if [[ "${RUN_TESTS}" == "1" ]]; then
|
|
36
|
+
log "==> swift test"
|
|
37
|
+
swift test -q
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
HOST_ARCH="$(uname -m)"
|
|
41
|
+
ARCHES_VALUE="${HOST_ARCH}"
|
|
42
|
+
if [[ -n "${RELEASE_ARCHES}" ]]; then
|
|
43
|
+
ARCHES_VALUE="${RELEASE_ARCHES}"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
log "==> package app"
|
|
47
|
+
SIGNING_MODE=adhoc ARCHES="${ARCHES_VALUE}" "${ROOT_DIR}/Scripts/package_app.sh" release
|
|
48
|
+
|
|
49
|
+
log "==> launch app"
|
|
50
|
+
if ! open "${APP_BUNDLE}"; then
|
|
51
|
+
log "WARN: open failed; launching binary directly."
|
|
52
|
+
"${APP_BUNDLE}/Contents/MacOS/${APP_NAME}" >/dev/null 2>&1 &
|
|
53
|
+
disown
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
for _ in {1..10}; do
|
|
57
|
+
if pgrep -f "${APP_PROCESS_PATTERN}" >/dev/null 2>&1; then
|
|
58
|
+
log "OK: ${APP_NAME} is running."
|
|
59
|
+
exit 0
|
|
60
|
+
fi
|
|
61
|
+
sleep 0.4
|
|
62
|
+
done
|
|
63
|
+
fail "App exited immediately. Check crash logs in Console.app (User Reports)."
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
6
|
+
APP_NAME=${APP_NAME:-MyApp}
|
|
7
|
+
APP_PATH="$PROJECT_ROOT/${APP_NAME}.app"
|
|
8
|
+
|
|
9
|
+
echo "==> Killing existing ${APP_NAME} instances"
|
|
10
|
+
pkill -x "$APP_NAME" || pkill -f "${APP_NAME}.app" || true
|
|
11
|
+
sleep 0.5
|
|
12
|
+
|
|
13
|
+
if [[ ! -d "$APP_PATH" ]]; then
|
|
14
|
+
echo "ERROR: ${APP_NAME}.app not found at $APP_PATH"
|
|
15
|
+
echo "Run ./Scripts/package_app.sh first to build the app"
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
echo "==> Launching ${APP_NAME} from $APP_PATH"
|
|
20
|
+
open -n "$APP_PATH"
|
|
21
|
+
|
|
22
|
+
sleep 1
|
|
23
|
+
if pgrep -x "$APP_NAME" > /dev/null; then
|
|
24
|
+
echo "OK: ${APP_NAME} is running."
|
|
25
|
+
else
|
|
26
|
+
echo "ERROR: App exited immediately. Check crash logs in Console.app (User Reports)."
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
|
5
|
+
ZIP=${1:?
|
|
6
|
+
"Usage: $0 MyApp-<ver>.zip"}
|
|
7
|
+
FEED_URL=${2:-"https://example.com/appcast.xml"}
|
|
8
|
+
PRIVATE_KEY_FILE=${SPARKLE_PRIVATE_KEY_FILE:-}
|
|
9
|
+
if [[ -z "$PRIVATE_KEY_FILE" ]]; then
|
|
10
|
+
echo "Set SPARKLE_PRIVATE_KEY_FILE to your ed25519 private key (Sparkle)." >&2
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
if [[ ! -f "$ZIP" ]]; then
|
|
14
|
+
echo "Zip not found: $ZIP" >&2
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
ZIP_DIR=$(cd "$(dirname "$ZIP")" && pwd)
|
|
19
|
+
ZIP_NAME=$(basename "$ZIP")
|
|
20
|
+
ZIP_BASE="${ZIP_NAME%.zip}"
|
|
21
|
+
VERSION=${SPARKLE_RELEASE_VERSION:-}
|
|
22
|
+
if [[ -z "$VERSION" ]]; then
|
|
23
|
+
if [[ "$ZIP_NAME" =~ ^[^-]+-([0-9]+(\.[0-9]+){1,2}([-.][^.]*)?)\.zip$ ]]; then
|
|
24
|
+
VERSION="${BASH_REMATCH[1]}"
|
|
25
|
+
else
|
|
26
|
+
echo "Could not infer version from $ZIP_NAME; set SPARKLE_RELEASE_VERSION." >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
NOTES_HTML="${ZIP_DIR}/${ZIP_BASE}.html"
|
|
32
|
+
KEEP_NOTES=${KEEP_SPARKLE_NOTES:-0}
|
|
33
|
+
if [[ -x "$ROOT/Scripts/changelog-to-html.sh" ]]; then
|
|
34
|
+
"$ROOT/Scripts/changelog-to-html.sh" "$VERSION" >"$NOTES_HTML"
|
|
35
|
+
else
|
|
36
|
+
cat >"$NOTES_HTML" <<HTML
|
|
37
|
+
<!doctype html>
|
|
38
|
+
<html lang="en">
|
|
39
|
+
<meta charset="utf-8">
|
|
40
|
+
<title>${ZIP_BASE}</title>
|
|
41
|
+
<body>
|
|
42
|
+
<h2>${ZIP_BASE}</h2>
|
|
43
|
+
<p>Release notes not provided.</p>
|
|
44
|
+
</body>
|
|
45
|
+
</html>
|
|
46
|
+
HTML
|
|
47
|
+
fi
|
|
48
|
+
cleanup() {
|
|
49
|
+
if [[ -n "${WORK_DIR:-}" ]]; then
|
|
50
|
+
rm -rf "$WORK_DIR"
|
|
51
|
+
fi
|
|
52
|
+
if [[ "$KEEP_NOTES" != "1" ]]; then
|
|
53
|
+
rm -f "$NOTES_HTML"
|
|
54
|
+
fi
|
|
55
|
+
}
|
|
56
|
+
trap cleanup EXIT
|
|
57
|
+
|
|
58
|
+
DOWNLOAD_URL_PREFIX=${SPARKLE_DOWNLOAD_URL_PREFIX:-"https://example.com/downloads/v${VERSION}/"}
|
|
59
|
+
|
|
60
|
+
if ! command -v generate_appcast >/dev/null; then
|
|
61
|
+
echo "generate_appcast not found in PATH. Install Sparkle tools." >&2
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
WORK_DIR=$(mktemp -d /tmp/appcast.XXXXXX)
|
|
66
|
+
|
|
67
|
+
cp "$ROOT/appcast.xml" "$WORK_DIR/appcast.xml"
|
|
68
|
+
cp "$ZIP" "$WORK_DIR/$ZIP_NAME"
|
|
69
|
+
cp "$NOTES_HTML" "$WORK_DIR/$ZIP_BASE.html"
|
|
70
|
+
|
|
71
|
+
pushd "$WORK_DIR" >/dev/null
|
|
72
|
+
generate_appcast \
|
|
73
|
+
--ed-key-file "$PRIVATE_KEY_FILE" \
|
|
74
|
+
--download-url-prefix "$DOWNLOAD_URL_PREFIX" \
|
|
75
|
+
--embed-release-notes \
|
|
76
|
+
--link "$FEED_URL" \
|
|
77
|
+
"$WORK_DIR"
|
|
78
|
+
popd >/dev/null
|
|
79
|
+
|
|
80
|
+
cp "$WORK_DIR/appcast.xml" "$ROOT/appcast.xml"
|
|
81
|
+
|
|
82
|
+
echo "Appcast generated (appcast.xml). Upload alongside $ZIP at $FEED_URL"
|