the manager lands in manager/, next to ios/ and web/. it is a fork of this repo's own app, not of feather, so scripts/apply-rebrand.sh excludes it the same way it excludes web/ — the generic feather-to- ftstore rule would rewrite its app.ftstore.manager identity and mangle the lineage notes in its docs. zsign and idevicekitten were vendored copies in the old repo. they are registered as submodules here instead, pinned to the same commits ios/ uses and verified byte-identical to what was vendored. that keeps 71 MB of duplicated source out of the tree and leaves the xcode project's relative paths intact, so project.pbxproj needed no edits. the server moves to ftstore.app in both apps: managerrepoclient, the seeded default source and managerconfig's fallback. downloadmanager keeps the old admin host in its user-agent allowlist — that check is permissive, not identifying, and dropping it would stop sending the header to installs whose stored override still names the old host. the rest of the admin rename lands too: the client id, the base-url environment variable, the info.plist key, and user-facing errors. the userdefaults override key is renamed with a one-time migration read, so an existing install keeps the address its owner configured instead of falling back to the default. tags gain a third namespace: manager-v* for releases, manager-dev for the rolling prerelease. both repos published to a tag called `dev` before; sharing it here would make each build overwrite the other's release assets.
3.6 KiB
FTStore Manager — project guide for AI agents
FTStore Manager is a stripped-down fork of FTStore (itself a fork of Feather, GPL-3.0). Its only job: install and update FTStore from a private FTStore Admin, after the user imports a signing certificate.
Monorepo. This used to be the separate
FTStuff/FTStore-Managerrepo; it now lives inmanager/insideFTStuff/FTStore, alongsideios/(the app it installs) andweb/(the FTStore Admin server it talks to). Read the root AGENTS.md first — it owns the tag namespaces (manager-v*,manager-dev) and the rule thatscripts/apply-rebrand.shmust never touch this directory.ZsignandIDeviceKittenare submodules here, not vendored copies; clone with--recurse-submodules.
Brand / identity
- App name
FTStore Manager· bundle idapp.ftstore.manager(must differ fromapp.ftstoreso installing FTStore is never a self-install → OTA works without pairing). - Internal Xcode target/scheme/product name is still
FTStore(only the display name and bundle id changed), somakeand the project file work unchanged.
How it works (the important part)
- The GitHub PAT is never in the app. Downloads go through the FTStore Admin proxy
(
FTStore Adminrepo:src/app/api/ftstore-app/manifest+/download), which holds the token server-side. The app only knows the FTStore Admin base URL. - Channels:
stable= newest non-devrelease with anFTStore*.ipaasset (version = tag);dev= thedev-tagged release, tracked by the asset'supdatedAt(the version string is constant). Compare logic lives inFTStore/Manager/FTStoreUpdateManager.swift. - Install: OTA only (itms-services via Vapor
ServerInstaller). The device-pairing method was removed.InstallPreviewViewalready uses OTA for a non-self-install.
Where things live
- New Manager code:
FTStore/Manager/*+FTStore/FTStoreManagerApp.swift(the@main). - Reused engine (unchanged):
Backend/Storage,Backend/Server,Backend/Observable(DownloadManager,AppInstallManager,OptionsManager,UpdateManager[inert]),Utilities/Handlers(sign/archive/cert/zsign/tweak),Utilities/{FR,CertificateReader,MachO,ARDecompression},Extensions, and the certificate/install/signing-setup views underViews/. - Config:
FTStore.xcconfig(FEATHER_PRODUCT_BUNDLE_IDENTIFIER,FTSTORE_ADMIN_BASE_URL) → injected intoInfo.plist(FTStoreAdminBaseURL). Never commit a real PAT.
Integration seams (when changing the engine)
AppInstallManager.install(InstallRequest)is the Manager's entry into the existing download → cert-gate → sign → install pipeline (reuses the private_startStoreDownload).FTStoreUpdateManagerreads installed state fromStorage.newestSignedApp(identifier: "app.ftstore").
Dependencies
Vendored (no submodules): Zsign, NimbleKit, AltSourceKit, IDeviceKitten. Remote
SPM: Vapor, Zip, SWCompression, Nuke, LicensePlist. AltSourceKit/IDeviceKitten/
LicensePlist stay linked because the engine still references a few helpers from them; they
can be pruned in Xcode if desired.
Build / validate
- macOS + Xcode only.
make→packages/FTStore-Manager.ipa, or theManager ReleaseGitHub Action. - Static checks (CI/Linux ok):
plistlib/jsonparse, and grep the repo + built binary forghp_/ any token — there must be none (the proxy design guarantees it).
GPL-3.0
Keep LICENSE and Feather/FTStore attribution intact; keep source public.