build.sh bash
175 lines 8.2 KB
Raw
sha256:bd1eb24434d281fe65142038c1bf217493421f5a86880c22dff7e6037d2d4700 feat(companion): add production macOS distribution path Human minor ⚠ breaking 25 days ago
1 #!/bin/bash
2 set -euo pipefail
3
4 repo_root="$(cd "$(dirname "$0")/../../.." && pwd)"
5 configuration="release"
6 input_dir="$repo_root/build/release-inputs"
7 output_dir="$repo_root/build/phase7"
8
9 while [[ $# -gt 0 ]]; do
10 case "$1" in
11 --configuration) configuration="$2"; shift 2 ;;
12 --inputs) input_dir="$2"; shift 2 ;;
13 --output) output_dir="$2"; shift 2 ;;
14 *) echo "unknown argument: $1" >&2; exit 2 ;;
15 esac
16 done
17
18 if [[ "$input_dir" != /* ]]; then input_dir="$repo_root/$input_dir"; fi
19 if [[ "$output_dir" != /* ]]; then output_dir="$repo_root/$output_dir"; fi
20
21 [[ "$(uname -s)" == "Darwin" ]] || { echo "macOS build host required" >&2; exit 1; }
22 [[ "$(uname -m)" == "arm64" ]] || { echo "arm64 build host required" >&2; exit 1; }
23 [[ -x "$input_dir/node/bin/node" ]] || { echo "verified Node input missing" >&2; exit 1; }
24 [[ -f "$input_dir/model/onnx/model_quantized.onnx" ]] || { echo "verified model input missing" >&2; exit 1; }
25 [[ -f "$repo_root/companion/runtime/package-lock.json" ]] || { echo "runtime package lock missing" >&2; exit 1; }
26 if [[ "${KNOWTATION_ALLOW_UNCOMMITTED_BUILD:-}" != "1" ]]; then
27 [[ "${KNOWTATION_SOURCE_MUSE_REVISION:-}" =~ ^sha256:[0-9a-f]{64}$ ]] || {
28 echo "exact KNOWTATION_SOURCE_MUSE_REVISION is required" >&2; exit 1;
29 }
30 [[ "${KNOWTATION_SOURCE_GIT_REVISION:-}" =~ ^[0-9a-f]{40}$ ]] || {
31 echo "exact KNOWTATION_SOURCE_GIT_REVISION is required" >&2; exit 1;
32 }
33 fi
34
35 rm -rf "$output_dir"
36 mkdir -p "$output_dir/clang-cache" "$output_dir/swiftpm-cache"
37 export CLANG_MODULE_CACHE_PATH="$output_dir/clang-cache"
38 export SWIFTPM_MODULECACHE_OVERRIDE="$output_dir/swiftpm-cache"
39
40 swift build \
41 --disable-sandbox \
42 --package-path "$repo_root/companion/macos" \
43 --configuration "$configuration" \
44 --scratch-path "$output_dir/swift"
45 bin_dir="$(swift build --disable-sandbox --package-path "$repo_root/companion/macos" --configuration "$configuration" --scratch-path "$output_dir/swift" --show-bin-path)"
46
47 app="$output_dir/unsigned/Knowtation.app"
48 resources="$app/Contents/Resources"
49 runtime="$resources/runtime"
50 custody_app="$app/Contents/Library/LaunchServices/KnowtationCustodyAgent.app"
51 mkdir -p \
52 "$app/Contents/MacOS" \
53 "$app/Contents/Helpers" \
54 "$app/Contents/Library/LaunchAgents" \
55 "$custody_app/Contents/MacOS" \
56 "$runtime"
57
58 cp "$repo_root/release/macos/plists/App-Info.plist" "$app/Contents/Info.plist"
59 cp "$repo_root/release/macos/plists/CustodyAgent-Info.plist" "$custody_app/Contents/Info.plist"
60 cp "$repo_root/release/macos/plists/LaunchAgent.plist" "$app/Contents/Library/LaunchAgents/store.knowtation.companion.custody.plist"
61 cp "$bin_dir/Knowtation" "$app/Contents/MacOS/Knowtation"
62 cp "$bin_dir/KnowtationCustodyAgent" "$custody_app/Contents/MacOS/KnowtationCustodyAgent"
63 cp "$bin_dir/knowtation" "$app/Contents/Helpers/knowtation"
64 cp "$bin_dir/knowtation-mcp" "$app/Contents/Helpers/knowtation-mcp"
65
66 ditto "$input_dir/node" "$runtime/node"
67 # The installed runtime executes only the fixed Node binary. Package managers,
68 # development headers, and their symlinks are build inputs and are not shipped.
69 rm -f "$runtime/node/bin/corepack" "$runtime/node/bin/npm" "$runtime/node/bin/npx"
70 rm -rf "$runtime/node/include" "$runtime/node/lib/node_modules" "$runtime/node/share"
71 ditto "$input_dir/model" "$runtime/models/all-MiniLM-L6-v2"
72
73 runtime_spec="$repo_root/release/macos/runtime-files.json"
74 while IFS= read -r directory; do
75 mkdir -p "$runtime/$directory"
76 ditto "$repo_root/$directory" "$runtime/$directory"
77 done < <(node -e 'const j=require(process.argv[1]); for(const p of j.sourceDirectories) console.log(p)' "$runtime_spec")
78
79 while IFS= read -r file; do
80 mkdir -p "$(dirname "$runtime/$file")"
81 cp "$repo_root/$file" "$runtime/$file"
82 done < <(node -e 'const j=require(process.argv[1]); for(const p of j.sourceFiles) console.log(p)' "$runtime_spec")
83
84 while IFS= read -r directory; do
85 mkdir -p "$runtime/$directory"
86 ditto "$repo_root/$directory" "$runtime/$directory"
87 done < <(node -e 'const j=require(process.argv[1]); for(const p of j.assetDirectories) console.log(p)' "$runtime_spec")
88
89 runtime_package="$output_dir/runtime-package"
90 mkdir -p "$runtime_package"
91 cp "$repo_root/companion/runtime/package.json" "$runtime_package/package.json"
92 cp "$repo_root/companion/runtime/package-lock.json" "$runtime_package/package-lock.json"
93 runtime_npm="$input_dir/node/bin/npm"
94 runtime_path="$input_dir/node/bin:/usr/bin:/bin:/usr/sbin:/sbin"
95 env PATH="$runtime_path" npm_config_cache="$output_dir/npm-cache" \
96 "$runtime_npm" --prefix "$runtime_package" ci --omit=dev --ignore-scripts
97 env PATH="$runtime_path" npm_config_cache="$output_dir/npm-cache" npm_config_build_from_source=true \
98 "$runtime_npm" --prefix "$runtime_package" rebuild argon2 better-sqlite3
99 rm -rf \
100 "$runtime_package/node_modules/.bin" \
101 "$runtime_package/node_modules/argon2/prebuilds" \
102 "$runtime_package/node_modules/sharp" \
103 "$runtime_package/node_modules/onnxruntime-node" \
104 "$runtime_package/node_modules/@img"
105 rm -f "$runtime_package/node_modules/better-sqlite3/build/Release/test_extension.node"
106 find "$runtime_package/node_modules" -maxdepth 1 -type d -name 'sqlite-vec-*' \
107 ! -name 'sqlite-vec-darwin-arm64' -exec rm -rf {} +
108 ditto "$runtime_package/node_modules" "$runtime/node_modules"
109 cp "$repo_root/companion/runtime/package-lock.json" "$runtime/release-package-lock.json"
110
111 verify_locked_file() {
112 local file="$1"
113 local expected="$2"
114 [[ -f "$file" ]] || { echo "locked runtime file missing: $file" >&2; exit 1; }
115 [[ "$(shasum -a 256 "$file" | awk '{print $1}')" == "$expected" ]] || {
116 echo "locked runtime file digest mismatch: $file" >&2; exit 1;
117 }
118 }
119 while IFS=$'\t' read -r relative expected; do
120 verify_locked_file "$runtime/$relative" "$expected"
121 done < <(node -e 'const j=require(process.argv[1]); for(const f of j.runtime.files) console.log(`${f.path}\t${f.sha256}`)' \
122 "$repo_root/release/macos/release-lock.json")
123 while IFS=$'\t' read -r relative expected; do
124 verify_locked_file "$runtime/models/all-MiniLM-L6-v2/$relative" "$expected"
125 done < <(node -e 'const j=require(process.argv[1]); for(const f of j.model.files) console.log(`${f.path}\t${f.sha256}`)' \
126 "$repo_root/release/macos/release-lock.json")
127
128 if find "$runtime/node_modules" -type d \( -name sharp -o -name 'sharp-*' -o -name 'libvips-*' \) -print -quit | grep -q .; then
129 echo "excluded sharp/libvips dependency entered runtime closure" >&2
130 exit 1
131 fi
132
133 for required_native in \
134 "$runtime/node_modules/argon2/build/Release/argon2.node" \
135 "$runtime/node_modules/better-sqlite3/build/Release/better_sqlite3.node" \
136 "$runtime/node_modules/sqlite-vec-darwin-arm64/vec0.dylib"; do
137 [[ -f "$required_native" ]] || { echo "required arm64 runtime missing: $required_native" >&2; exit 1; }
138 done
139 while IFS= read -r -d '' native; do
140 [[ "$(lipo -archs "$native")" == "arm64" ]] || {
141 echo "non-arm64 native runtime entered closure: $native" >&2; exit 1;
142 }
143 done < <(find "$runtime" -type f \( -name '*.node' -o -name '*.dylib' \) -print0)
144
145 node --experimental-vm-modules --no-warnings \
146 "$repo_root/scripts/release/macos/verify-module-closure.mjs" --runtime "$runtime"
147
148 export SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:?SOURCE_DATE_EPOCH is required}"
149 node "$repo_root/scripts/release/macos/generate-sbom.mjs" \
150 --node-modules "$runtime/node_modules" \
151 --package-lock "$repo_root/companion/runtime/package-lock.json" \
152 --release-lock "$repo_root/release/macos/release-lock.json" \
153 --node-license "$input_dir/node/LICENSE" \
154 --license-templates "$repo_root/release/macos/licenses" \
155 --license-overrides "$repo_root/release/macos/license-overrides.json" \
156 --sbom "$resources/sbom.spdx.json" \
157 --notices "$resources/THIRD-PARTY-NOTICES.txt"
158
159 cp "$repo_root/release/macos/release-lock.json" "$resources/release-lock.json"
160 cp "$repo_root/release/macos/update-trust.json" "$resources/update-trust.json"
161 chmod 755 \
162 "$app/Contents/MacOS/Knowtation" \
163 "$app/Contents/Helpers/knowtation" \
164 "$app/Contents/Helpers/knowtation-mcp" \
165 "$custody_app/Contents/MacOS/KnowtationCustodyAgent" \
166 "$runtime/node/bin/node"
167
168 node "$repo_root/scripts/release/macos/generate-manifest.mjs" \
169 --stage unsigned \
170 --app "$app" \
171 --output "$resources/runtime-manifest.json"
172 mkdir -p "$output_dir/manifests"
173 cp "$resources/runtime-manifest.json" "$output_dir/manifests/unsigned-runtime-manifest.json"
174
175 echo "$app"
File History 1 commit
sha256:bd1eb24434d281fe65142038c1bf217493421f5a86880c22dff7e6037d2d4700 feat(companion): add production macOS distribution path Human minor ⚠ 25 days ago