@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.
- package/CHANGELOG.md +45 -0
- package/README.md +5 -5
- package/README.tr.md +2 -2
- package/docs/FIGMA_PIPELINE.md +1 -1
- package/docs/adr/0001-three-model-triage.md +4 -2
- package/docs/architecture.md +2 -2
- package/docs/ecosystem.md +13 -11
- package/docs/features.md +2 -2
- package/index.js +1 -1
- package/install/_common.mjs +25 -1
- package/install/_dev-only-files.mjs +2 -2
- package/install/_mcp-register.mjs +4 -3
- package/install/_plugin-skills.mjs +1 -3
- package/install/copilot.mjs +18 -9
- package/install/index.mjs +2 -4
- package/install/templates/copilot-instructions.md +7 -7
- package/package.json +1 -1
- package/pipeline/claude-md-template.md +2 -2
- package/pipeline/commands/multi-agent/SKILL.md +5 -5
- package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/design-check/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/help/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/review/SKILL.md +27 -14
- package/pipeline/commands/multi-agent/review-analysis/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/store-ready/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/sync/SKILL.md +2 -2
- package/pipeline/commands/sim-test.md +54 -15
- package/pipeline/lib/credential-inventory.sh +15 -2
- package/pipeline/lib/credential-store-resolver.sh +14 -4
- package/pipeline/lib/credential-store.sh +8 -2
- package/pipeline/lib/extract-conventions.sh +1 -14
- package/pipeline/lib/fetch-confluence.sh +12 -4
- package/pipeline/lib/fetch-crashlytics.sh +11 -8
- package/pipeline/lib/fetch-document.sh +1 -1
- package/pipeline/lib/fetch-figma-annotations.sh +7 -5
- package/pipeline/lib/fetch-fortify.sh +5 -3
- package/pipeline/lib/fetch-graylog.sh +5 -3
- package/pipeline/lib/figma-mcp-refresh.sh +1 -1
- package/pipeline/lib/figma-screenshot.sh +27 -24
- package/pipeline/lib/figma-token.sh +8 -4
- package/pipeline/lib/issue-fetcher.sh +0 -1
- package/pipeline/lib/jira-publish.sh +7 -5
- package/pipeline/lib/md2confluence-v3.py +13 -7
- package/pipeline/lib/multi-repo-pipeline.sh +18 -8
- package/pipeline/lib/plan-todos.sh +11 -0
- package/pipeline/lib/post-pr-review.sh +9 -2
- package/pipeline/lib/repo-cache.sh +18 -10
- package/pipeline/lib/review-watch.sh +60 -14
- package/pipeline/lib/shadow-git.sh +8 -4
- package/pipeline/lib/vercel-deploy.sh +2 -2
- package/pipeline/multi-agent-refs/_dev-context.md +5 -2
- package/pipeline/multi-agent-refs/analysis/locked.md +4 -4
- package/pipeline/multi-agent-refs/analysis/render.md +1 -1
- package/pipeline/multi-agent-refs/cross-cli-contract.md +1 -1
- package/pipeline/multi-agent-refs/outside-the-pipeline.md +6 -6
- package/pipeline/multi-agent-refs/phases/log-format.md +1 -1
- package/pipeline/multi-agent-refs/phases/modes.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +4 -2
- package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +3 -3
- package/pipeline/multi-agent-refs/phases/phase-2-planning.md +5 -5
- package/pipeline/multi-agent-refs/phases/phase-4-review.md +21 -16
- package/pipeline/multi-agent-refs/tracker-contract.md +1 -1
- package/pipeline/rules/figma-pipeline.md +18 -72
- package/pipeline/rules/outside-the-pipeline.md +4 -3
- package/pipeline/schemas/agent-state.schema.json +1 -1
- package/pipeline/schemas/token-budget.json +1 -1
- package/pipeline/scripts/_stack-routing.mjs +1 -1
- package/pipeline/scripts/agent-guard.py +102 -21
- package/pipeline/scripts/anonymize-findings.mjs +7 -6
- package/pipeline/scripts/build-skills-index.mjs +14 -3
- package/pipeline/scripts/cost-budget-check.mjs +5 -3
- package/pipeline/scripts/cost-lib.sh +0 -15
- package/pipeline/scripts/diff-explain.mjs +22 -12
- package/pipeline/scripts/gc-refs.sh +6 -2
- package/pipeline/scripts/gc-tmp.sh +1 -1
- package/pipeline/scripts/gc-worktrees.sh +1 -1
- package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
- package/pipeline/scripts/github-ssh-setup.sh +7 -2
- package/pipeline/scripts/graph-build.mjs +2 -2
- package/pipeline/scripts/jira-wiki-escape.mjs +2 -1
- package/pipeline/scripts/keychain.py +12 -11
- package/pipeline/scripts/learning-curve.mjs +1 -1
- package/pipeline/scripts/migrate-prefs.mjs +1 -1
- package/pipeline/scripts/output-quality-check.sh +3 -1
- package/pipeline/scripts/phase-tracker.sh +1 -1
- package/pipeline/scripts/phase0-exit-gate.mjs +2 -1
- package/pipeline/scripts/plan-coverage-gate.mjs +2 -1
- package/pipeline/scripts/pre-commit-check.sh +23 -13
- package/pipeline/scripts/prune-logs.sh +1 -1
- package/pipeline/scripts/render-agent-log-cost.sh +3 -1
- package/pipeline/scripts/render-cost-summary.sh +4 -2
- package/pipeline/scripts/render-work-summary.sh +5 -3
- package/pipeline/scripts/repo-map.mjs +3 -2
- package/pipeline/scripts/scan-skills.sh +6 -2
- package/pipeline/scripts/search-logs.sh +8 -6
- package/pipeline/scripts/sign-skills.sh +3 -1
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +1 -1
- package/pipeline/scripts/triage-memory.mjs +25 -4
- package/pipeline/scripts/uninstall.mjs +20 -12
- package/pipeline/scripts/update-check.sh +2 -2
- package/pipeline/scripts/update-issue-progress.sh +6 -5
- package/pipeline/scripts/validate-analysis-doc.mjs +6 -6
- package/pipeline/scripts/verify-skills.sh +3 -1
- package/pipeline/scripts/worktree-finalize.sh +22 -10
- package/pipeline/skills/.skill-manifest.json +81 -57
- package/pipeline/skills/.skills-index.json +19 -19
- package/pipeline/skills/shared/README.md +8 -8
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +7 -7
- package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +23 -14
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +2 -2
- package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +56 -0
- package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +0 -4
- package/pipeline/skills/shared/external/api-patterns/SKILL.md +12 -24
- package/pipeline/skills/shared/external/app-store-changelog/references/release-notes-guidelines.md +34 -0
- package/pipeline/skills/shared/external/app-store-changelog/scripts/collect_release_changes.sh +33 -0
- package/pipeline/skills/shared/external/architecture/SKILL.md +7 -9
- package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +0 -4
- package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +0 -1
- package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +0 -14
- package/pipeline/skills/shared/external/hig-components-content/SKILL.md +13 -13
- package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +16 -16
- package/pipeline/skills/shared/external/hig-components-status/SKILL.md +6 -6
- package/pipeline/skills/shared/external/hig-components-system/SKILL.md +13 -13
- package/pipeline/skills/shared/external/hig-foundations/SKILL.md +23 -23
- package/pipeline/skills/shared/external/hig-inputs/SKILL.md +18 -18
- package/pipeline/skills/shared/external/hig-patterns/SKILL.md +30 -30
- package/pipeline/skills/shared/external/hig-platforms/SKILL.md +11 -11
- package/pipeline/skills/shared/external/hig-technologies/SKILL.md +33 -33
- package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +52 -52
- package/pipeline/skills/shared/external/ios-coding-standard/references/lint-local.sh +1 -1
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +11 -11
- package/pipeline/skills/shared/external/ios-developer/SKILL.md +0 -1
- package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +7 -3
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +9 -15
- package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +0 -5
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/Package.swift +17 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/Resources/.keep +0 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/main.swift +11 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/version.env +2 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/build_icon.sh +49 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/compile_and_run.sh +63 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/launch.sh +28 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/make_appcast.sh +82 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/package_app.sh +206 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/setup_dev_signing.sh +52 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/sign-and-notarize.sh +52 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/version.env +2 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/references/packaging.md +17 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/references/release.md +32 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/references/scaffold.md +79 -0
- package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +0 -1
- package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +0 -4
- package/pipeline/skills/shared/external/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
- package/pipeline/skills/shared/external/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
- package/pipeline/skills/shared/external/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
- package/pipeline/skills/shared/external/swiftui-performance-audit/references/code-smells.md +150 -0
- package/pipeline/skills/shared/external/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
- package/pipeline/skills/shared/external/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
- package/pipeline/skills/shared/external/swiftui-performance-audit/references/profiling-intake.md +44 -0
- package/pipeline/skills/shared/external/swiftui-performance-audit/references/report-template.md +47 -0
- package/pipeline/skills/shared/external/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
- package/pipeline/skills/shared/external/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/app-wiring.md +201 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/async-state.md +96 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/components-index.md +46 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/controls.md +57 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/deeplinks.md +66 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/focus.md +90 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/form.md +97 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/grids.md +71 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/haptics.md +71 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/input-toolbar.md +51 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/list.md +86 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/macos-settings.md +71 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/matched-transitions.md +59 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/media.md +73 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/menu-bar.md +101 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/navigationstack.md +159 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/overlay.md +45 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/performance.md +62 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/previews.md +48 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/scrollview.md +87 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/searchable.md +71 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/sheets.md +155 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/split-views.md +72 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/tabview.md +114 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/theming.md +71 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/title-menus.md +93 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/top-bar.md +49 -0
- package/pipeline/skills/shared/external/swiftui-view-refactor/references/mv-patterns.md +161 -0
- package/pipeline/skills/skills-index.md +8 -8
- 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)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
+
)
|
|
File without changes
|
package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/build_icon.sh
ADDED
|
@@ -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"
|
package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/compile_and_run.sh
ADDED
|
@@ -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
|
package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/make_appcast.sh
ADDED
|
@@ -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"
|
package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/package_app.sh
ADDED
|
@@ -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,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.
|