Repository navigation
Expand file tree
/
Copy pathproject.yml
More file actions
407 lines (258 loc) · 13 KB
/
Copy pathproject.yml
File metadata and controls
407 lines (258 loc) · 13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# XcodeGen spec. Regenerate with `just project` after editing.
#
# TranscriptsCore is compiled straight into the app target — the shared surface
# is six files and this app has zero SPM dependencies, so a package indirection
# would be ceremony. TranscriptsActivity is compiled into both the app and the
# widget extension: ActivityKit matches the attributes type across the two
# processes, so one shared definition.
name: Transcripts
packages:
Transcripts:
path: .
options:
bundleIdPrefix: ltd.hatcher
deploymentTarget:
iOS: "17.0"
createIntermediateGroups: true
targets:
Transcripts:
type: application
platform: iOS
sources:
- path: Sources/Transcripts
# The Mac pipeline is excluded rather than compiled and left unused. It is
# dead code on iOS — the phone's chat chain is FoundationModels then the
# extractive fallback, never Ollama — but compiling it linked URLSession
# and URLRequest into the shipped binary. The App Store privacy answer and
# the review notes both claim those symbols are absent and invite Apple to
# verify it against the binary, so leaving them in made a checkable claim
# false. Excluded here, not #if'd, so the Mac package still builds it.
- path: Sources/TranscriptsCore
excludes:
- "Providers/OllamaClient.swift" # the only URLSession in the app
- "Providers/CommandRunner.swift" # Process — unavailable on iOS
- "Providers/TemplateEngine.swift" # PipelineEngine only
- "Providers/ExternalStageResult.swift"
# PipelineStage.swift and PipelineContext.swift stay: StageID is the
# config file's stage vocabulary, which AppConfig decodes on iOS too.
- "Pipeline/PipelineEngine.swift" # drives external commands
- "Stages/**" # Summarize/Classify build OllamaClient
- path: Sources/TranscriptsActivity
dependencies:
- target: TranscriptsWidgets
embed: true
# A generated plist file, NOT GENERATE_INFOPLIST_FILE + INFOPLIST_KEY_*.
# Those settings only cover a fixed list of scalar keys: UIBackgroundModes is
# an array and was silently dropped, so the app had no background audio at
# all. iOS then suspended it on backgrounding, which killed the audio session
# mid-recording and left the m4a unfinalized (2026-08-10, in the ancestor
# codebase).
info:
path: Sources/Transcripts/Info.plist
properties:
CFBundleDisplayName: Transcripts
# A manually-specified info plist does NOT inherit MARKETING_VERSION /
# CURRENT_PROJECT_VERSION the way GENERATE_INFOPLIST_FILE would — the
# keys silently default to 1.0/1, which is the version App Store Connect
# validates uploads against. Thread the build settings through by hand.
CFBundleShortVersionString: $(MARKETING_VERSION)
CFBundleVersion: $(CURRENT_PROJECT_VERSION)
# The entire point of a pocket recorder: capture survives the screen
# locking and the user switching apps. An Info.plist key, not a
# paid-membership entitlement, so it works under free provisioning.
UIBackgroundModes: [audio]
# Lets the recorder show a Dynamic Island / Lock Screen activity, the
# only signal capture is still alive once the app backgrounds.
NSSupportsLiveActivities: true
NSMicrophoneUsageDescription: Transcripts records meetings and voice notes from your microphone.
# Live text is transcribed on-device only; audio is never sent to a server.
NSSpeechRecognitionUsageDescription: Transcripts transcribes your recording on this device as you speak, so you can read it live.
# Only HTTPS via system frameworks — skips the export-compliance
# questionnaire on every App Store build upload.
ITSAppUsesNonExemptEncryption: false
# Puts Transcripts in the share sheet for audio, and lets Files "Open
# with" hand a recording over. A share extension would do the same at
# the cost of a second bundle id and an App Group to reach the
# destination bookmark — this needs neither.
CFBundleDocumentTypes:
- CFBundleTypeName: Audio
LSHandlerRank: Alternate
CFBundleTypeRole: Editor
LSItemContentTypes:
- public.audio
- public.mp3
- public.mpeg-4-audio
- com.apple.m4a-audio
- public.aiff-audio
- com.microsoft.waveform-audio
# Opens the file where it sits rather than only a copy, so a recording
# can be imported without first being duplicated into the app.
LSSupportsOpeningDocumentsInPlace: true
UILaunchScreen: {}
UISupportedInterfaceOrientations:
- UIInterfaceOrientationPortrait
UISupportedInterfaceOrientations~ipad:
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: ltd.hatcher.transcripts
GENERATE_INFOPLIST_FILE: NO
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
MARKETING_VERSION: "1.1.3"
CURRENT_PROJECT_VERSION: "1"
# Free provisioning re-signs weekly; leaving the team unset lets Xcode
# pick the personal one without baking an ID into the repo.
CODE_SIGN_STYLE: Automatic
TARGETED_DEVICE_FAMILY: "1,2"
# WidgetKit extension hosting the Live Activity.
TranscriptsWidgets:
type: app-extension
platform: iOS
sources:
- path: Sources/TranscriptsWidgets
- path: Sources/TranscriptsActivity
# A widget extension needs a nested NSExtension dictionary, which the
# INFOPLIST_KEY_* build settings cannot express — installd rejects the appex
# outright without it.
info:
path: Sources/TranscriptsWidgets/Info.plist
properties:
CFBundleDisplayName: Transcripts
# Must match the host app's versions or the archive fails validation.
CFBundleShortVersionString: $(MARKETING_VERSION)
CFBundleVersion: $(CURRENT_PROJECT_VERSION)
NSExtension:
NSExtensionPointIdentifier: com.apple.widgetkit-extension
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: ltd.hatcher.transcripts.widgets
GENERATE_INFOPLIST_FILE: NO
MARKETING_VERSION: "1.1.3"
CURRENT_PROJECT_VERSION: "1"
CODE_SIGN_STYLE: Automatic
SKIP_INSTALL: YES
TARGETED_DEVICE_FAMILY: "1,2"
# The macOS menu-bar app. An Xcode target rather than a SwiftPM executable:
# SwiftPM cannot emit an .app bundle, and — more sharply — a package and a
# generated .xcodeproj sharing a directory both offer a "Transcripts" scheme,
# where xcodebuild silently resolves the project. Building the Mac app then
# built the iOS one instead. One project, distinct scheme names, no ambiguity.
TranscriptsMac:
type: application
platform: macOS
deploymentTarget: "14.0"
sources:
- path: Sources/TranscriptsMac
excludes: ["Support/Info.plist", "Support/*.entitlements"]
- path: Sources/TranscriptsMac/Support/Transcripts.icns
buildPhase: resources
dependencies:
- package: Transcripts
product: TranscriptsCore
- package: Transcripts
product: TranscriptsEngine
# Every key must be declared here. `info.path` GENERATES the plist rather
# than copying an existing one, so the hand-ported file that used to live at
# that path was silently overwritten — taking LSUIElement, both TCC usage
# strings and the icon with it. Nothing failed loudly: the app still built,
# still launched, and still recorded, it just grew a Dock icon and lost the
# sentences macOS shows when asking for the microphone.
info:
path: Sources/TranscriptsMac/Support/Info.plist
properties:
CFBundleDisplayName: Transcripts
CFBundleName: Transcripts
# An agent app: menu bar only, no Dock icon, no menu bar of its own.
LSUIElement: true
LSMinimumSystemVersion: "14.0"
CFBundleIconFile: Transcripts
CFBundleShortVersionString: $(MARKETING_VERSION)
CFBundleVersion: $(CURRENT_PROJECT_VERSION)
NSMicrophoneUsageDescription: Transcripts records meetings and voice notes from your microphone.
NSSpeechRecognitionUsageDescription: Transcripts transcribes your recordings on this device to create readable transcripts.
# Shown by the system-audio permission dialog (Core Audio process tap —
# see SystemAudioTap.swift). Optional by design: declining leaves
# recordings microphone-only.
NSAudioCaptureUsageDescription: Transcripts records this Mac's audio during calls, so the other participants' side is included. Recordings work without it — they are just microphone-only.
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: ltd.hatcher.transcripts
PRODUCT_NAME: Transcripts
GENERATE_INFOPLIST_FILE: NO
MARKETING_VERSION: "1.1.3"
CURRENT_PROJECT_VERSION: "1"
# Unsandboxed by necessity: ScreenCaptureKit system audio and an
# arbitrary user-chosen vault path. Signed without entitlements — a
# self-signed build carrying sandbox entitlements is a known way to end
# up "authorized" by TCC but fed silence.
ENABLE_APP_SANDBOX: NO
CODE_SIGN_STYLE: Manual
CODE_SIGN_IDENTITY: "Transcripts Local Signing"
CODE_SIGN_ENTITLEMENTS: ""
TranscriptsMacStore:
type: application
platform: macOS
deploymentTarget: "14.0"
sources:
- path: Sources/TranscriptsMac
excludes: ["Support/Info.plist", "Support/InfoStore.plist", "Support/*.entitlements"]
- path: Sources/TranscriptsMac/Support/Transcripts.icns
buildPhase: resources
dependencies:
- package: Transcripts
product: TranscriptsCore
- package: Transcripts
product: TranscriptsEngine
# Every key must be declared here. `info.path` GENERATES the plist rather
# than copying an existing one, so the hand-ported file that used to live at
# that path was silently overwritten — taking LSUIElement, both TCC usage
# strings and the icon with it. Nothing failed loudly: the app still built,
# still launched, and still recorded, it just grew a Dock icon and lost the
# sentences macOS shows when asking for the microphone.
info:
path: Sources/TranscriptsMac/Support/InfoStore.plist
properties:
CFBundleDisplayName: Transcripts
CFBundleName: Transcripts
# An agent app: menu bar only, no Dock icon, no menu bar of its own.
LSUIElement: true
LSMinimumSystemVersion: "14.0"
CFBundleIconFile: Transcripts
CFBundleShortVersionString: $(MARKETING_VERSION)
CFBundleVersion: $(CURRENT_PROJECT_VERSION)
# The store wants a category, and asks the encryption question on every
# upload unless the answer is in the binary.
LSApplicationCategoryType: public.app-category.productivity
ITSAppUsesNonExemptEncryption: false
NSMicrophoneUsageDescription: Transcripts records meetings and voice notes from your microphone.
NSSpeechRecognitionUsageDescription: Transcripts transcribes your recordings on this device to create readable transcripts.
# Shown by the system-audio permission dialog (Core Audio process tap —
# see SystemAudioTap.swift). Optional by design: declining leaves
# recordings microphone-only.
NSAudioCaptureUsageDescription: Transcripts records this Mac's audio during calls, so the other participants' side is included. Recordings work without it — they are just microphone-only.
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: ltd.hatcher.transcripts
PRODUCT_NAME: Transcripts
GENERATE_INFOPLIST_FILE: NO
MARKETING_VERSION: "1.1.3"
CURRENT_PROJECT_VERSION: "1"
# The Mac App Store build. Same sources and bundle identifier as
# TranscriptsMac (so one App Store Connect record serves iPhone, iPad
# and Mac), but sandboxed, and compiled with APP_STORE so that what the
# store does not allow is left out rather than failing at runtime:
# shell commands, launching other programs, updating itself, moving
# itself into /Applications. See StoreEdition.swift.
#
# The sandbox was proven before this target existed (sandbox-spike):
# the Core Audio tap still hears system audio, and folders the user
# picks stay reachable across launches through FolderAccess.
ENABLE_APP_SANDBOX: YES
ENABLE_HARDENED_RUNTIME: YES
CODE_SIGN_STYLE: Automatic
DEVELOPMENT_TEAM: 6Q9BX97LMS
CODE_SIGN_ENTITLEMENTS: Sources/TranscriptsMac/Support/TranscriptsStore.entitlements
SWIFT_ACTIVE_COMPILATION_CONDITIONS: "$(inherited) APP_STORE"