@mmerterden/multi-agent-pipeline 16.18.0 → 16.19.0

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.
Files changed (200) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +5 -5
  3. package/README.tr.md +2 -2
  4. package/docs/FIGMA_PIPELINE.md +1 -1
  5. package/docs/adr/0001-three-model-triage.md +4 -2
  6. package/docs/architecture.md +2 -2
  7. package/docs/ecosystem.md +13 -11
  8. package/docs/features.md +2 -2
  9. package/index.js +1 -1
  10. package/install/_common.mjs +25 -1
  11. package/install/_dev-only-files.mjs +2 -2
  12. package/install/_mcp-register.mjs +4 -3
  13. package/install/_plugin-skills.mjs +1 -3
  14. package/install/copilot.mjs +18 -9
  15. package/install/index.mjs +2 -4
  16. package/install/templates/copilot-instructions.md +7 -7
  17. package/package.json +1 -1
  18. package/pipeline/claude-md-template.md +2 -2
  19. package/pipeline/commands/multi-agent/SKILL.md +5 -5
  20. package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +1 -1
  21. package/pipeline/commands/multi-agent/design-check/SKILL.md +1 -1
  22. package/pipeline/commands/multi-agent/help/SKILL.md +2 -2
  23. package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -1
  24. package/pipeline/commands/multi-agent/review/SKILL.md +27 -14
  25. package/pipeline/commands/multi-agent/review-analysis/SKILL.md +1 -1
  26. package/pipeline/commands/multi-agent/store-ready/SKILL.md +2 -2
  27. package/pipeline/commands/multi-agent/sync/SKILL.md +2 -2
  28. package/pipeline/commands/sim-test.md +54 -15
  29. package/pipeline/lib/credential-inventory.sh +15 -2
  30. package/pipeline/lib/credential-store-resolver.sh +14 -4
  31. package/pipeline/lib/credential-store.sh +8 -2
  32. package/pipeline/lib/extract-conventions.sh +1 -14
  33. package/pipeline/lib/fetch-confluence.sh +12 -4
  34. package/pipeline/lib/fetch-crashlytics.sh +11 -8
  35. package/pipeline/lib/fetch-document.sh +1 -1
  36. package/pipeline/lib/fetch-figma-annotations.sh +7 -5
  37. package/pipeline/lib/fetch-fortify.sh +5 -3
  38. package/pipeline/lib/fetch-graylog.sh +5 -3
  39. package/pipeline/lib/figma-mcp-refresh.sh +1 -1
  40. package/pipeline/lib/figma-screenshot.sh +27 -24
  41. package/pipeline/lib/figma-token.sh +8 -4
  42. package/pipeline/lib/issue-fetcher.sh +0 -1
  43. package/pipeline/lib/jira-publish.sh +7 -5
  44. package/pipeline/lib/md2confluence-v3.py +13 -7
  45. package/pipeline/lib/multi-repo-pipeline.sh +18 -8
  46. package/pipeline/lib/plan-todos.sh +11 -0
  47. package/pipeline/lib/post-pr-review.sh +9 -2
  48. package/pipeline/lib/repo-cache.sh +18 -10
  49. package/pipeline/lib/review-watch.sh +60 -14
  50. package/pipeline/lib/shadow-git.sh +8 -4
  51. package/pipeline/lib/vercel-deploy.sh +2 -2
  52. package/pipeline/multi-agent-refs/_dev-context.md +5 -2
  53. package/pipeline/multi-agent-refs/analysis/locked.md +4 -4
  54. package/pipeline/multi-agent-refs/analysis/render.md +1 -1
  55. package/pipeline/multi-agent-refs/cross-cli-contract.md +1 -1
  56. package/pipeline/multi-agent-refs/outside-the-pipeline.md +6 -6
  57. package/pipeline/multi-agent-refs/phases/log-format.md +1 -1
  58. package/pipeline/multi-agent-refs/phases/modes.md +1 -1
  59. package/pipeline/multi-agent-refs/phases/phase-0-init.md +4 -2
  60. package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +3 -3
  61. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +5 -5
  62. package/pipeline/multi-agent-refs/phases/phase-4-review.md +21 -16
  63. package/pipeline/multi-agent-refs/tracker-contract.md +1 -1
  64. package/pipeline/rules/figma-pipeline.md +18 -72
  65. package/pipeline/rules/outside-the-pipeline.md +4 -3
  66. package/pipeline/schemas/agent-state.schema.json +1 -1
  67. package/pipeline/schemas/token-budget.json +1 -1
  68. package/pipeline/scripts/_stack-routing.mjs +1 -1
  69. package/pipeline/scripts/agent-guard.py +102 -21
  70. package/pipeline/scripts/anonymize-findings.mjs +7 -6
  71. package/pipeline/scripts/build-skills-index.mjs +14 -3
  72. package/pipeline/scripts/cost-budget-check.mjs +5 -3
  73. package/pipeline/scripts/cost-lib.sh +0 -15
  74. package/pipeline/scripts/diff-explain.mjs +22 -12
  75. package/pipeline/scripts/gc-refs.sh +6 -2
  76. package/pipeline/scripts/gc-tmp.sh +1 -1
  77. package/pipeline/scripts/gc-worktrees.sh +1 -1
  78. package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
  79. package/pipeline/scripts/github-ssh-setup.sh +7 -2
  80. package/pipeline/scripts/graph-build.mjs +2 -2
  81. package/pipeline/scripts/jira-wiki-escape.mjs +2 -1
  82. package/pipeline/scripts/keychain.py +12 -11
  83. package/pipeline/scripts/learning-curve.mjs +1 -1
  84. package/pipeline/scripts/migrate-prefs.mjs +1 -1
  85. package/pipeline/scripts/output-quality-check.sh +3 -1
  86. package/pipeline/scripts/phase-tracker.sh +1 -1
  87. package/pipeline/scripts/phase0-exit-gate.mjs +2 -1
  88. package/pipeline/scripts/plan-coverage-gate.mjs +2 -1
  89. package/pipeline/scripts/pre-commit-check.sh +23 -13
  90. package/pipeline/scripts/prune-logs.sh +1 -1
  91. package/pipeline/scripts/render-agent-log-cost.sh +3 -1
  92. package/pipeline/scripts/render-cost-summary.sh +4 -2
  93. package/pipeline/scripts/render-work-summary.sh +5 -3
  94. package/pipeline/scripts/repo-map.mjs +3 -2
  95. package/pipeline/scripts/scan-skills.sh +6 -2
  96. package/pipeline/scripts/search-logs.sh +8 -6
  97. package/pipeline/scripts/sign-skills.sh +3 -1
  98. package/pipeline/scripts/smoke-cross-cli-behavior.sh +1 -1
  99. package/pipeline/scripts/triage-memory.mjs +25 -4
  100. package/pipeline/scripts/uninstall.mjs +20 -12
  101. package/pipeline/scripts/update-check.sh +2 -2
  102. package/pipeline/scripts/update-issue-progress.sh +6 -5
  103. package/pipeline/scripts/validate-analysis-doc.mjs +6 -6
  104. package/pipeline/scripts/verify-skills.sh +3 -1
  105. package/pipeline/scripts/worktree-finalize.sh +22 -10
  106. package/pipeline/skills/.skill-manifest.json +81 -57
  107. package/pipeline/skills/.skills-index.json +19 -19
  108. package/pipeline/skills/shared/README.md +8 -8
  109. package/pipeline/skills/shared/core/multi-agent/SKILL.md +7 -7
  110. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +1 -1
  111. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -2
  112. package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +1 -1
  113. package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +2 -2
  114. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +23 -14
  115. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +2 -2
  116. package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +56 -0
  117. package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +0 -4
  118. package/pipeline/skills/shared/external/api-patterns/SKILL.md +12 -24
  119. package/pipeline/skills/shared/external/app-store-changelog/references/release-notes-guidelines.md +34 -0
  120. package/pipeline/skills/shared/external/app-store-changelog/scripts/collect_release_changes.sh +33 -0
  121. package/pipeline/skills/shared/external/architecture/SKILL.md +7 -9
  122. package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +0 -4
  123. package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +0 -1
  124. package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +0 -14
  125. package/pipeline/skills/shared/external/hig-components-content/SKILL.md +13 -13
  126. package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +16 -16
  127. package/pipeline/skills/shared/external/hig-components-status/SKILL.md +6 -6
  128. package/pipeline/skills/shared/external/hig-components-system/SKILL.md +13 -13
  129. package/pipeline/skills/shared/external/hig-foundations/SKILL.md +23 -23
  130. package/pipeline/skills/shared/external/hig-inputs/SKILL.md +18 -18
  131. package/pipeline/skills/shared/external/hig-patterns/SKILL.md +30 -30
  132. package/pipeline/skills/shared/external/hig-platforms/SKILL.md +11 -11
  133. package/pipeline/skills/shared/external/hig-technologies/SKILL.md +33 -33
  134. package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +52 -52
  135. package/pipeline/skills/shared/external/ios-coding-standard/references/lint-local.sh +1 -1
  136. package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +11 -11
  137. package/pipeline/skills/shared/external/ios-developer/SKILL.md +0 -1
  138. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +7 -3
  139. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +9 -15
  140. package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +0 -5
  141. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/Package.swift +17 -0
  142. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/Resources/.keep +0 -0
  143. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/main.swift +11 -0
  144. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/version.env +2 -0
  145. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/build_icon.sh +49 -0
  146. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/compile_and_run.sh +63 -0
  147. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/launch.sh +28 -0
  148. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/make_appcast.sh +82 -0
  149. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/package_app.sh +206 -0
  150. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/setup_dev_signing.sh +52 -0
  151. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/sign-and-notarize.sh +52 -0
  152. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/version.env +2 -0
  153. package/pipeline/skills/shared/external/macos-spm-app-packaging/references/packaging.md +17 -0
  154. package/pipeline/skills/shared/external/macos-spm-app-packaging/references/release.md +32 -0
  155. package/pipeline/skills/shared/external/macos-spm-app-packaging/references/scaffold.md +79 -0
  156. package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +0 -1
  157. package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +0 -4
  158. package/pipeline/skills/shared/external/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
  159. package/pipeline/skills/shared/external/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
  160. package/pipeline/skills/shared/external/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
  161. package/pipeline/skills/shared/external/swiftui-performance-audit/references/code-smells.md +150 -0
  162. package/pipeline/skills/shared/external/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
  163. package/pipeline/skills/shared/external/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
  164. package/pipeline/skills/shared/external/swiftui-performance-audit/references/profiling-intake.md +44 -0
  165. package/pipeline/skills/shared/external/swiftui-performance-audit/references/report-template.md +47 -0
  166. package/pipeline/skills/shared/external/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
  167. package/pipeline/skills/shared/external/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
  168. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/app-wiring.md +201 -0
  169. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/async-state.md +96 -0
  170. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/components-index.md +46 -0
  171. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/controls.md +57 -0
  172. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/deeplinks.md +66 -0
  173. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/focus.md +90 -0
  174. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/form.md +97 -0
  175. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/grids.md +71 -0
  176. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/haptics.md +71 -0
  177. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  178. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  179. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/list.md +86 -0
  180. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  181. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/macos-settings.md +71 -0
  182. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  183. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/media.md +73 -0
  184. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/menu-bar.md +101 -0
  185. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/navigationstack.md +159 -0
  186. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/overlay.md +45 -0
  187. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/performance.md +62 -0
  188. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/previews.md +48 -0
  189. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  190. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/scrollview.md +87 -0
  191. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/searchable.md +71 -0
  192. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/sheets.md +155 -0
  193. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/split-views.md +72 -0
  194. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/tabview.md +114 -0
  195. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/theming.md +71 -0
  196. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/title-menus.md +93 -0
  197. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/top-bar.md +49 -0
  198. package/pipeline/skills/shared/external/swiftui-view-refactor/references/mv-patterns.md +161 -0
  199. package/pipeline/skills/skills-index.md +8 -8
  200. package/pipeline/skills/shared/external/help-skills/SKILL.md +0 -166
@@ -1,21 +1,15 @@
1
1
  ---
2
2
  name: localization-reuse-map
3
3
  description: >-
4
- Produce a per-screen localization-reuse map for one redesigned screen (iOS / Android / web) so content
5
- management can decide whether existing translations can be reused. For one screen it ties each UI element to
6
- its NEW (redesign) localization key + values, its LEGACY key + values per platform, AND the content team's
7
- ACTUAL final copy (CMS) read live from Figma Dev Mode annotations - old key, new key, old translations, new
8
- translations, CMS copy - recommends a reuse verdict (reuse / review / new) the content team confirms, renders
9
- a visual key-to-UI overlay plus a per-key red-box screenpiece for every table row, and publishes a Confluence
10
- page LIVE (idempotent - re-running a screen updates its page in place). New side = the redesign app's key
11
- usage + the authored/suggested translation values + the design component registry; legacy side = the legacy
12
- app's keys (iOS `"Key".localized` / Android `@string/Key` / web `t('key')` i18n calls) and its label
13
- service; CMS side = Figma annotations
14
- via REST API / MCP / local fallback. Also scans the implemented screen for error and dynamic keys the registry
15
- misses. Use it when mapping a redesigned screen's strings to the legacy ones for reuse, one screen at a time.
16
- Trigger phrases - "localization reuse map", "map old keys to new keys for this screen", "which legacy
17
- translations can we reuse", "reuse existing translations", "CMS copy from Figma annotations", "localization
18
- excel", "CMS import sheet", "/localization-reuse-map".
4
+ Produce a per-screen localization-reuse map for one redesigned screen (iOS / Android / web): for each UI
5
+ element it pairs the NEW localization key + values with the LEGACY key + values per platform and the
6
+ content team's ACTUAL CMS copy read live from Figma Dev Mode annotations, recommends a reuse verdict
7
+ (reuse / review / new) the content team confirms, renders a key-to-UI overlay plus a per-key red-box
8
+ screenpiece, and publishes a Confluence page live (idempotent). Also scans the implemented screen for
9
+ error and dynamic keys the registry misses. Use when mapping a redesigned screen's strings to the
10
+ legacy ones for reuse, one screen at a time. Trigger phrases - "localization reuse map", "map old keys
11
+ to new keys for this screen", "which legacy translations can we reuse", "reuse existing translations",
12
+ "CMS copy from Figma annotations", "localization excel", "CMS import sheet", "/localization-reuse-map".
19
13
  ---
20
14
 
21
15
  # Localization Reuse Map - old↔new localization map for one screen
@@ -103,8 +103,3 @@ spctl --assess --type execute --verbose build/HelloApp.app
103
103
  - Remove Sparkle steps if you do not use Sparkle for updates.
104
104
  - Sparkle relies on the bundle build number (`CFBundleVersion`), so `BUILD_NUMBER` in `version.env` must increase for each update.
105
105
  - For menu bar apps, set `MENU_BAR_APP=1` when packaging to emit `LSUIElement` in Info.plist.
106
- ```
107
-
108
- ---
109
-
110
- All 22 SKILL.md files have been fetched and presented above with their complete raw content. The content was retrieved via `curl` directly from `raw.githubusercontent.com` to ensure nothing was summarized or truncated. One note: the **firebase** skill file appears to have a truncated sentence in the original source itself ("You advocate for Firebase w") -- that is how it exists in the repository, not a fetch artifact.
@@ -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
+ )
@@ -0,0 +1,11 @@
1
+ import SwiftUI
2
+
3
+ @main
4
+ struct MyApp: App {
5
+ var body: some Scene {
6
+ WindowGroup {
7
+ Text("Hello from MyApp")
8
+ .padding()
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,2 @@
1
+ MARKETING_VERSION=0.1.0
2
+ BUILD_NUMBER=1
@@ -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"
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ CONF=${1:-release}
5
+ ROOT=$(cd "$(dirname "$0")/.." && pwd)
6
+ cd "$ROOT"
7
+
8
+ APP_NAME=${APP_NAME:-MyApp}
9
+ BUNDLE_ID=${BUNDLE_ID:-com.example.myapp}
10
+ MACOS_MIN_VERSION=${MACOS_MIN_VERSION:-14.0}
11
+ MENU_BAR_APP=${MENU_BAR_APP:-0}
12
+ SIGNING_MODE=${SIGNING_MODE:-}
13
+ APP_IDENTITY=${APP_IDENTITY:-}
14
+
15
+ if [[ -f "$ROOT/version.env" ]]; then
16
+ source "$ROOT/version.env"
17
+ else
18
+ MARKETING_VERSION=${MARKETING_VERSION:-0.1.0}
19
+ BUILD_NUMBER=${BUILD_NUMBER:-1}
20
+ fi
21
+
22
+ ARCH_LIST=( ${ARCHES:-} )
23
+ if [[ ${#ARCH_LIST[@]} -eq 0 ]]; then
24
+ HOST_ARCH=$(uname -m)
25
+ ARCH_LIST=("$HOST_ARCH")
26
+ fi
27
+
28
+ for ARCH in "${ARCH_LIST[@]}"; do
29
+ swift build -c "$CONF" --arch "$ARCH"
30
+ done
31
+
32
+ APP="$ROOT/${APP_NAME}.app"
33
+ rm -rf "$APP"
34
+ mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources" "$APP/Contents/Frameworks"
35
+
36
+ # Convert Icon.icon to Icon.icns if present (requires iconutil).
37
+ ICON_SOURCE="$ROOT/Icon.icon"
38
+ ICON_TARGET="$ROOT/Icon.icns"
39
+ if [[ -f "$ICON_SOURCE" ]]; then
40
+ iconutil --convert icns --output "$ICON_TARGET" "$ICON_SOURCE"
41
+ fi
42
+
43
+ LSUI_VALUE="false"
44
+ if [[ "$MENU_BAR_APP" == "1" ]]; then
45
+ LSUI_VALUE="true"
46
+ fi
47
+
48
+ BUILD_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
49
+ GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
50
+
51
+ cat > "$APP/Contents/Info.plist" <<PLIST
52
+ <?xml version="1.0" encoding="UTF-8"?>
53
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
54
+ <plist version="1.0">
55
+ <dict>
56
+ <key>CFBundleName</key><string>${APP_NAME}</string>
57
+ <key>CFBundleDisplayName</key><string>${APP_NAME}</string>
58
+ <key>CFBundleIdentifier</key><string>${BUNDLE_ID}</string>
59
+ <key>CFBundleExecutable</key><string>${APP_NAME}</string>
60
+ <key>CFBundlePackageType</key><string>APPL</string>
61
+ <key>CFBundleShortVersionString</key><string>${MARKETING_VERSION}</string>
62
+ <key>CFBundleVersion</key><string>${BUILD_NUMBER}</string>
63
+ <key>LSMinimumSystemVersion</key><string>${MACOS_MIN_VERSION}</string>
64
+ <key>LSUIElement</key><${LSUI_VALUE}/>
65
+ <key>CFBundleIconFile</key><string>Icon</string>
66
+ <key>BuildTimestamp</key><string>${BUILD_TIMESTAMP}</string>
67
+ <key>GitCommit</key><string>${GIT_COMMIT}</string>
68
+ </dict>
69
+ </plist>
70
+ PLIST
71
+
72
+ build_product_path() {
73
+ local name="$1"
74
+ local arch="$2"
75
+ case "$arch" in
76
+ arm64|x86_64) echo ".build/${arch}-apple-macosx/$CONF/$name" ;;
77
+ *) echo ".build/$CONF/$name" ;;
78
+ esac
79
+ }
80
+
81
+ verify_binary_arches() {
82
+ local binary="$1"; shift
83
+ local expected=("$@")
84
+ local actual
85
+ actual=$(lipo -archs "$binary")
86
+ local actual_count expected_count
87
+ actual_count=$(wc -w <<<"$actual" | tr -d ' ')
88
+ expected_count=${#expected[@]}
89
+ if [[ "$actual_count" -ne "$expected_count" ]]; then
90
+ echo "ERROR: $binary arch mismatch (expected: ${expected[*]}, actual: ${actual})" >&2
91
+ exit 1
92
+ fi
93
+ for arch in "${expected[@]}"; do
94
+ if [[ "$actual" != *"$arch"* ]]; then
95
+ echo "ERROR: $binary missing arch $arch (have: ${actual})" >&2
96
+ exit 1
97
+ fi
98
+ done
99
+ }
100
+
101
+ install_binary() {
102
+ local name="$1"
103
+ local dest="$2"
104
+ local binaries=()
105
+ for arch in "${ARCH_LIST[@]}"; do
106
+ local src
107
+ src=$(build_product_path "$name" "$arch")
108
+ if [[ ! -f "$src" ]]; then
109
+ echo "ERROR: Missing ${name} build for ${arch} at ${src}" >&2
110
+ exit 1
111
+ fi
112
+ binaries+=("$src")
113
+ done
114
+ if [[ ${#ARCH_LIST[@]} -gt 1 ]]; then
115
+ lipo -create "${binaries[@]}" -output "$dest"
116
+ else
117
+ cp "${binaries[0]}" "$dest"
118
+ fi
119
+ chmod +x "$dest"
120
+ verify_binary_arches "$dest" "${ARCH_LIST[@]}"
121
+ }
122
+
123
+ install_binary "$APP_NAME" "$APP/Contents/MacOS/$APP_NAME"
124
+
125
+ # Bundle app resources (if any).
126
+ APP_RESOURCES_DIR="$ROOT/Sources/$APP_NAME/Resources"
127
+ if [[ -d "$APP_RESOURCES_DIR" ]]; then
128
+ cp -R "$APP_RESOURCES_DIR/." "$APP/Contents/Resources/"
129
+ fi
130
+
131
+ # SwiftPM resource bundles are emitted next to the built binary.
132
+ PREFERRED_BUILD_DIR="$(dirname "$(build_product_path "$APP_NAME" "${ARCH_LIST[0]}")")"
133
+ shopt -s nullglob
134
+ SWIFTPM_BUNDLES=("${PREFERRED_BUILD_DIR}/"*.bundle)
135
+ shopt -u nullglob
136
+ if [[ ${#SWIFTPM_BUNDLES[@]} -gt 0 ]]; then
137
+ for bundle in "${SWIFTPM_BUNDLES[@]}"; do
138
+ cp -R "$bundle" "$APP/Contents/Resources/"
139
+ done
140
+ fi
141
+
142
+ # Embed frameworks if any exist in the build folder.
143
+ FRAMEWORK_DIRS=(".build/$CONF" ".build/${ARCH_LIST[0]}-apple-macosx/$CONF")
144
+ for dir in "${FRAMEWORK_DIRS[@]}"; do
145
+ if compgen -G "${dir}/*.framework" >/dev/null; then
146
+ cp -R "${dir}/"*.framework "$APP/Contents/Frameworks/"
147
+ chmod -R a+rX "$APP/Contents/Frameworks"
148
+ install_name_tool -add_rpath "@executable_path/../Frameworks" "$APP/Contents/MacOS/$APP_NAME"
149
+ break
150
+ fi
151
+ done
152
+
153
+ if [[ -f "$ICON_TARGET" ]]; then
154
+ cp "$ICON_TARGET" "$APP/Contents/Resources/Icon.icns"
155
+ fi
156
+
157
+ # Ensure contents are writable before stripping attributes and signing.
158
+ chmod -R u+w "$APP"
159
+
160
+ # Strip extended attributes to prevent AppleDouble files that break code sealing.
161
+ xattr -cr "$APP"
162
+ find "$APP" -name '._*' -delete
163
+
164
+ ENTITLEMENTS_DIR="$ROOT/.build/entitlements"
165
+ DEFAULT_ENTITLEMENTS="$ENTITLEMENTS_DIR/${APP_NAME}.entitlements"
166
+ mkdir -p "$ENTITLEMENTS_DIR"
167
+
168
+ APP_ENTITLEMENTS=${APP_ENTITLEMENTS:-$DEFAULT_ENTITLEMENTS}
169
+ if [[ ! -f "$APP_ENTITLEMENTS" ]]; then
170
+ cat > "$APP_ENTITLEMENTS" <<PLIST
171
+ <?xml version="1.0" encoding="UTF-8"?>
172
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
173
+ <plist version="1.0">
174
+ <dict>
175
+ <!-- Add entitlements here if needed. -->
176
+ </dict>
177
+ </plist>
178
+ PLIST
179
+ fi
180
+
181
+ if [[ "$SIGNING_MODE" == "adhoc" || -z "$APP_IDENTITY" ]]; then
182
+ CODESIGN_ARGS=(--force --sign "-")
183
+ else
184
+ CODESIGN_ARGS=(--force --timestamp --options runtime --sign "$APP_IDENTITY")
185
+ fi
186
+
187
+ # Sign embedded frameworks and their nested binaries before the app bundle.
188
+ sign_frameworks() {
189
+ local fw
190
+ for fw in "$APP/Contents/Frameworks/"*.framework; do
191
+ if [[ ! -d "$fw" ]]; then
192
+ continue
193
+ fi
194
+ while IFS= read -r -d '' bin; do
195
+ codesign "${CODESIGN_ARGS[@]}" "$bin"
196
+ done < <(find "$fw" -type f -perm -111 -print0)
197
+ codesign "${CODESIGN_ARGS[@]}" "$fw"
198
+ done
199
+ }
200
+ sign_frameworks
201
+
202
+ codesign "${CODESIGN_ARGS[@]}" \
203
+ --entitlements "$APP_ENTITLEMENTS" \
204
+ "$APP"
205
+
206
+ echo "Created $APP"
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env bash
2
+ # Setup stable development code signing to reduce keychain prompts.
3
+ set -euo pipefail
4
+
5
+ APP_NAME=${APP_NAME:-MyApp}
6
+ CERT_NAME="${APP_NAME} Development"
7
+
8
+ if security find-certificate -c "$CERT_NAME" >/dev/null 2>&1; then
9
+ echo "Certificate '$CERT_NAME' already exists."
10
+ echo "Export this in your shell profile:"
11
+ echo " export APP_IDENTITY='$CERT_NAME'"
12
+ exit 0
13
+ fi
14
+
15
+ echo "Creating self-signed certificate '$CERT_NAME'..."
16
+
17
+ TEMP_CONFIG=$(mktemp)
18
+ trap "rm -f $TEMP_CONFIG" EXIT
19
+
20
+ cat > "$TEMP_CONFIG" <<EOFCONF
21
+ [ req ]
22
+ distinguished_name = req_distinguished_name
23
+ x509_extensions = v3_req
24
+ prompt = no
25
+
26
+ [ req_distinguished_name ]
27
+ CN = $CERT_NAME
28
+ O = ${APP_NAME} Development
29
+ C = US
30
+
31
+ [ v3_req ]
32
+ keyUsage = critical,digitalSignature
33
+ extendedKeyUsage = codeSigning
34
+ EOFCONF
35
+
36
+ openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 \
37
+ -nodes -keyout /tmp/dev.key -out /tmp/dev.crt \
38
+ -config "$TEMP_CONFIG" 2>/dev/null
39
+
40
+ openssl pkcs12 -export -out /tmp/dev.p12 \
41
+ -inkey /tmp/dev.key -in /tmp/dev.crt \
42
+ -passout pass: 2>/dev/null
43
+
44
+ security import /tmp/dev.p12 -k ~/Library/Keychains/login.keychain-db \
45
+ -T /usr/bin/codesign -T /usr/bin/security
46
+
47
+ rm -f /tmp/dev.{key,crt,p12}
48
+
49
+ echo ""
50
+ echo "Trust this certificate for code signing in Keychain Access."
51
+ echo "Then export in your shell profile:"
52
+ echo " export APP_IDENTITY='$CERT_NAME'"
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ APP_NAME=${APP_NAME:-MyApp}
5
+ APP_IDENTITY=${APP_IDENTITY:-"Developer ID Application: Example (TEAMID)"}
6
+ APP_BUNDLE="${APP_NAME}.app"
7
+ ROOT=$(cd "$(dirname "$0")/.." && pwd)
8
+ source "$ROOT/version.env"
9
+ ZIP_NAME="${APP_NAME}-${MARKETING_VERSION}.zip"
10
+
11
+ if [[ -z "${APP_STORE_CONNECT_API_KEY_P8:-}" || -z "${APP_STORE_CONNECT_KEY_ID:-}" || -z "${APP_STORE_CONNECT_ISSUER_ID:-}" ]]; then
12
+ echo "Missing APP_STORE_CONNECT_* env vars (API key, key id, issuer id)." >&2
13
+ exit 1
14
+ fi
15
+
16
+ echo "$APP_STORE_CONNECT_API_KEY_P8" | sed 's/\\n/\n/g' > /tmp/app-store-connect-key.p8
17
+ trap 'rm -f /tmp/app-store-connect-key.p8 /tmp/${APP_NAME}Notarize.zip' EXIT
18
+
19
+ ARCHES_VALUE=${ARCHES:-"arm64 x86_64"}
20
+ ARCH_LIST=( ${ARCHES_VALUE} )
21
+ for ARCH in "${ARCH_LIST[@]}"; do
22
+ swift build -c release --arch "$ARCH"
23
+ done
24
+ ARCHES="${ARCHES_VALUE}" "$ROOT/Scripts/package_app.sh" release
25
+
26
+ ENTITLEMENTS_DIR="$ROOT/.build/entitlements"
27
+ APP_ENTITLEMENTS="${APP_ENTITLEMENTS:-${ENTITLEMENTS_DIR}/${APP_NAME}.entitlements}"
28
+
29
+ codesign --force --timestamp --options runtime --sign "$APP_IDENTITY" \
30
+ --entitlements "$APP_ENTITLEMENTS" \
31
+ "$APP_BUNDLE"
32
+
33
+ DITTO_BIN=${DITTO_BIN:-/usr/bin/ditto}
34
+ "$DITTO_BIN" --norsrc -c -k --keepParent "$APP_BUNDLE" "/tmp/${APP_NAME}Notarize.zip"
35
+
36
+ xcrun notarytool submit "/tmp/${APP_NAME}Notarize.zip" \
37
+ --key /tmp/app-store-connect-key.p8 \
38
+ --key-id "$APP_STORE_CONNECT_KEY_ID" \
39
+ --issuer "$APP_STORE_CONNECT_ISSUER_ID" \
40
+ --wait
41
+
42
+ xcrun stapler staple "$APP_BUNDLE"
43
+
44
+ xattr -cr "$APP_BUNDLE"
45
+ find "$APP_BUNDLE" -name '._*' -delete
46
+
47
+ "$DITTO_BIN" --norsrc -c -k --keepParent "$APP_BUNDLE" "$ZIP_NAME"
48
+
49
+ spctl -a -t exec -vv "$APP_BUNDLE"
50
+ stapler validate "$APP_BUNDLE"
51
+
52
+ echo "Done: $ZIP_NAME"
@@ -0,0 +1,2 @@
1
+ MARKETING_VERSION=0.1.0
2
+ BUILD_NUMBER=1
@@ -0,0 +1,17 @@
1
+ # Packaging notes
2
+
3
+ ## Build output paths
4
+ SwiftPM places binaries under:
5
+ - `.build/<arch>-apple-macosx/<config>/<AppName>` for arch-specific builds
6
+ - `.build/<config>/<AppName>` for some products (frameworks/tools)
7
+
8
+ Use `ARCHES="arm64 x86_64"` with `swift build` to produce universal binaries.
9
+
10
+ ## Common environment variables (used by templates)
11
+ - `APP_NAME`: App/binary name (for example, `MyApp`).
12
+ - `BUNDLE_ID`: Bundle identifier (for example, `com.example.myapp`).
13
+ - `ARCHES`: Space-separated architectures (default: host arch).
14
+ - `SIGNING_MODE`: `adhoc` to avoid keychain prompts in dev.
15
+ - `APP_IDENTITY`: Codesigning identity name for release builds.
16
+ - `MACOS_MIN_VERSION`: Minimum macOS version for Info.plist.
17
+ - `MENU_BAR_APP`: Set to `1` to add `LSUIElement` to Info.plist.