Status menu rebuilt around the D11 eight-item whitelist: header summary
(running status, mode, active target path), proxy toggle, mode picker with
checkmark, read-only active-target cascade over the catalog tree, update
all subscriptions, copy HTTP export line, open main window, and quit that
states the proxy keeps running in the background. Out-of-whitelist items
(copy PAC URL) removed. Two global shortcuts (KeyboardShortcuts 3.1.0)
toggle the proxy and cycle modes through the same controller entry points
as the menu.
Presentation logic extracted to StatusMenuModel (state summary mapping,
HTTP export line, mode cycle, read-only target tree) with unit tests;
activeTargetID is now published so the menu stays live when activation
happens while the proxy is off.
Ports as explicit user configuration (spec #21 D8): factory defaults
1086/1087/1089, named validation errors (range + pairwise-distinct),
free-port suggestion over 32768-65535 excluding other endpoints'
configured values, best-effort occupancy probe (bind test + lsof
process name), and persisted listen settings that refuse silent port
rewrites - an unreadable store stops the runtime with a named launch
failure instead of deploying placeholder ports. PAC-port changes
surface the shared-URL invalidation notice (UI lands with #33).
Runtime bind failure keeps flowing through the #29 health gate:
launch failed, system proxy untouched.
Shipped 1.x builds all carried CFBundleVersion 1: the old
Info.plist hardcoded it and the release flow only set the
marketing version. Same bundle id, so NG2 must exceed 1.
AGENTS.md keeps only the agent contract: hook enable step, gate
behavior, manual commands, rule-tuning policy. Install steps,
tool baselines, and config rationale are human-facing setup and
now live in README's 代码风格工具 section.
Update stale pointers that sent readers to AGENTS.md for tool
install (root AGENTS.md, pre-commit hook comment and error
message); hook behavior unchanged.
Pin sslocal v1.25.0 (aarch64-apple-darwin) and v2ray-plugin v1.3.2 via
committed manifests (tag + asset URL + archive SHA-256 + bundle location +
sign identifier):
- Scripts/fetch-external-binaries.sh downloads the pinned archive, verifies
its SHA-256 byte-for-byte, extracts only the named member (arm64-only
check) and stamps the local cache; archive hash mismatch fails hard, and
any manifest/local-artifact drift forces a re-verified refetch. It re-runs
as a pre-build phase so tampering fails the build itself.
- project.yml installs both binaries via Copy Files into
Contents/Helpers[/Plugins]; generate requires the artifacts to exist
(fetch before generate, else Copy Files phases are silently dropped).
- Scripts/sign-embedded-helpers.sh re-signs each helper Developer ID with
--options runtime --timestamp and the pinned identifier
(<bundle-id>[.plugin.]<name>) before Xcode seals the outer app signature.
- Scripts/packaging-gate.sh asserts strict nested signature verification,
DevID + Hardened Runtime on the app with no App Sandbox entitlement, and
exact per-binary manifest coverage under Contents/Helpers.
- Tests pin both manifests' schema and anchor hashes.
Verified: build + gate all green; byte-flip, foreign-binary and
missing-binary tampers each caught; 5 unit tests pass; no submodules or
in-repo builds; notarization stays out of scope (#39).
- ShadowsocksX-NG2/.swift-format: Apple Swift 6.4 toolchain default rules snapshot
- ShadowsocksX-NG2/.swiftlint.yml: default rules, excludes build artifacts and Legacy/
- .githooks/pre-commit: format staged NG2 Swift files into the index, then SwiftLint;
error-severity violations reject the commit; non-NG2 files pass through untouched
- ShadowsocksX-NG2/AGENTS.md: NG2-scoped conventions (tiered below root AGENTS.md)
- normalize skeleton sources to swift format baseline (2-space indent)
XcodeGen-managed SwiftUI menu bar app in ShadowsocksX-NG2/: LSUIElement,
inherited bundle id com.qiuyuzhou.ShadowsocksX-NG, macOS 15 arm64,
Hardened Runtime + Developer ID signing, empty entitlements dict (no App
Sandbox; Release disables base entitlement injection). Placeholder status
menu and main window; unit test target wired into the app scheme. Test
bundles sign with the Apple Development cert so Hardened Runtime library
validation accepts injection. Generated .xcodeproj and plists are
gitignored; project.yml is the source of truth. Legacy/ untouched.
Closes#22
Wayfinder #19: plugin program references persist verbatim, only managed
plugins are selectable, unavailable plugins are invalid activation
candidates, and plugin options are sensitive in their entirety.
- Remove GitHub Actions workflows and issue templates
- Move legacy ShadowsocksX-NG project into Legacy/
- Remove git submodules; dependencies will use prebuilt
binaries copied from upstream releases instead of
building in-repo
- Add ShadowsocksX-NG2/ directory for the new project
- Update .gitignore paths for the new layout
Improve the clarity of notifications in the QR code scanning feature:
1. Permission handling:
- Show notification when screen recording permission is missing
- Automatically open system settings for permission grant
2. Enhanced scanning status notifications:
When no QR code found:
- Title: "Scanned X displays"
- Subtitle: "No QR codes found"
- Body: "Try adjusting the QR code position on your screen"
When invalid QR codes found:
- Title: "Found X QR code(s)"
- Subtitle: "No valid Shadowsocks URLs"
- Body: "QR codes found are not Shadowsocks configuration"
When valid QR codes found:
- Title: "Found X Shadowsocks URL(s)"
- Subtitle: "Scanned X displays, found X QR codes"
- Body: "Successfully added X server configuration(s)"