Commit Graph
660 Commits
Author SHA1 Message Date
Qiu Yuzhou fd9be86149 refactor(ng2): add diagnostics workflow module as single UI-facing seam
诊断区收敛为 DiagnosticsWorkflow 深 module(Candidate 03,issue #43):事实
采样、轮询代际、raw 日志投影、报告准备与导出完成登记集中一个 seam,视图只
负责生命周期触发、呈现、剪贴板、保存面板与报告文件写入。侧栏与详情共享同
一份安全摘要;收集只读,不触碰目录、凭据、runtime 与系统代理设置。

目录不再把原始 ConfigurationCatalog 写入诊断快照:CatalogWorkflow 只输出
domain-neutral 聚合事实(计数 + 已知无效数),报告 builder 只接受已裁剪的
report facts。事件导出改为显式白名单派生(diagnosticReportLine):自由
detail、主机公布地址与 runtime 错误原文一律清洗,数量/端口/领域点名原因
保留;新增事件漏 case 无法编译。raw GUI 事件行与 wrapper agent.log 尾部仅
经显式查看/复制提供,永不进入报告(ADR-0006)。导出完成事件只在用户选择的
文件实际写入成功后登记。

RuntimeEventStore 事件改为携带封闭枚举原值,渲染发生在呈现边缘(白名单清
洗只可能作用于原值)。测试:新增 workflow interface 覆盖投毒导出、白名单、
raw/报告分离、缺失标注、只读、代际覆盖与取消;ADR-0006 与 CONTEXT.md 术语
同步入库。
2026-09-22 19:22:31 +08:00
Qiu Yuzhou 3df1624d91 refactor(ng2): add settings workflow module as single UI-facing seam
建立设置工作流深 module(App/SettingsWorkflow/),把设置编辑的编排从视图
收拢到一个 seam,镜像 #41 的目录工作流模式:

- UI-facing interface:可编辑 draft 投影(binding 直连)、占用/校验/门禁/
  保存中/待确认 PAC 失效提示/错误等只读投影,与 suggestPort、save、
  confirmPACNotice、cancelPACNotice、reset、reloadFromCommitted 等 typed
  command;登录启动项是独立偏好域(ADR-0005),视图直连其控制器,不经本
  module。
- implementation(灰置):端口占用探测的 Task.detached 编排(代际去竞态)、
  保存门禁(validationErrors+占用)、「当前运行端口」例外、PAC 失效确认
  流、重置事务与 ProxySettingsStoreError 文案映射。
- isOn 判定从 StatusMenuModel 迁至 ProxyRuntimeController.ProxyState 扩展,
  菜单摘要与设置工作流共用同一事实来源;设置视图不再持有
  ProxyRuntimeController 与探测缝,组合根在 MainApp 接线一次,设置窗口
  scene 的显式触达路径不变。

测试:设置编辑 workflow 不经 SwiftUI 即可全测——占用反应与门禁阻塞、
运行端口例外放行、PAC 失效确认/取消、校验阻塞、提交失败保留旧值并点名、
重置回出厂、建议端口只写草稿(8 项;全量 376 项通过)。

Out of scope:设置视觉重设计、ProxyRuntimeController 拆分、独立编译
target。
2026-09-22 17:36:40 +08:00
Qiu Yuzhou e242bbf426 feat(ng2): persist proxy mode selection and drop enabled-modes
模式选择(菜单唯一入口)随设置快照持久化,GUI 重启恢复所选模式;持久化
失败保留旧模式并点名呈现,不静默切换。外部 PAC 模式下保存设置时,模式从
新快照解析后与 URL 一起作为一个逻辑变更提交(清空 URL 回落 PAC 并同步
持久化),校验失败先于写入。重置偏好把模式回 PAC。

enabledModes 自 ADR-0002 停止偏好迁移后无任何写入方,且 2.0 无编辑 UI,
按死状态删除:内置三模式恒可选,外部 PAC 仍以已配置的有效 URL 为门槛
(ADR-0004)。

测试:模式持久化与重启恢复、持久化失败保留旧值、外部 PAC 一个逻辑变更
回落;makeController 的 proxyMode 参数改为可选以便测试走恢复路径。
2026-09-22 17:36:24 +08:00
Qiu Yuzhou 376b648ac4 refactor(login): independent opt-in login item
Drop the UserDefaults intent mirror and read the toggle state only from the
system login-item registration status (approval-pending counts as enabled);
default to off until the user enables it, and stop resetting it with proxy
preferences (ADR-0005).
2026-09-22 17:32:46 +08:00
Qiu Yuzhou a7b1b1629a refactor(settings): remove proxy mode selector
Keep mode switching in the status menu as the common control.
2026-09-22 16:31:14 +08:00
Qiu Yuzhou 3dc6043dc6 refactor(ng2): remove system-level shortcuts
Keep proxy controls explicit and leave existing shortcut preferences untouched.
2026-09-22 16:16:58 +08:00
Qiu Yuzhou 46ebe1d835 feat(ng2): simplify Legacy import and isolate default ports (#42) 2026-09-22 14:26:58 +08:00
Qiu Yuzhou 2fe401cd50 feat(ng2): add catalog workflow module as single UI-facing seam (#41)
建立目录工作流深 module(App/CatalogWorkflow/),收窄主窗口与配置 UI 对
配置目录、凭据存储、订阅快照、Legacy 导入与运行时收敛的访问:

- UI-facing interface:非敏感树/编辑面/订阅 projection、opaque NodeID 查询、
  typed command(ServerEditDraft 等)、typed error 与 structured outcome
  (BatchImportOutcome 逐行点名、RemovalOutcome selection invalidation);
  秘密值只在显式编辑/分享/订阅 URL 命令中出现。
- 服务器编辑:配置与凭据作为一个逻辑变更,CredentialWriteJournal 保证目录
  持久化失败时旧配置与旧凭据都保持有效(story 12/13,含测试)。
- 提交与收敛分离:目录提交成功与 runtimeSync 收敛阶段是独立观察面,运行时
  失败不回滚已提交目录(story 38/39,含测试)。
- 订阅:创建/刷新/换址/删除沿用原子快照、last-good 保留与凭据回滚;卡片
  projection 只含 host,结构化刷新状态由呈现层本地化。
- Legacy 导入端到端编排:不驱动运行时收敛、不自动重复、显式再导入创建独立
  分组;handoff 仍经组合根注入的独立边界。
- Deletion test:删除 CatalogViewModel/Types/+Subscriptions 旧 facade,全部
  视图与状态菜单迁移到新 seam;选择、pane、sheet、alert 状态收归 UI 持有
  (ErrorAlertPresenter)。导入失败行以行号点名,不再回显 ss:// 行内容。

测试经 module interface 观察(395 项全部通过):持久化失败凭据回滚、提交/
收敛阶段分离、收敛失败不回滚、导入不触发运行时等新增场景;既有 Domain、
协调器与运行时测试保持不变。

Out of scope(spec #41):设置编辑、ProxyRuntimeController、Legacy handoff、
新视觉设计、独立编译 target。
2026-09-22 11:39:07 +08:00
Qiu Yuzhou 374f0da4d7 feat(ng2): decouple catalog commit from proxy runtime sync (#40)
Add an application-layer CatalogCommitCoordinator as the single commit
entry for normal configuration changes: copy -> mutate -> atomic persist
-> publish committed state -> async runtime convergence toward the just
committed in-memory snapshot. Commits complete at persist; convergence
reports structured outcomes (converged / revalidated / failed /
clearedAndStopped) and never blocks or rolls back the commit. Each commit
bumps a generation; superseded syncs end before starting or have their
late results discarded, so only the latest snapshot can win. No automatic
retry.

CatalogRuntimeSyncing is the one new replacement seam: the production
ProxyRuntimeSyncAdapter drives the existing ProxyRuntimeController via a
snapshot-based catalogDidCommit; tests use a deterministic fake. When no
active target exists a commit no longer touches the runtime at all.

CatalogViewModel stays as a compatibility facade with unchanged published
state; the optional postCommit callback and the per-scene callback wiring
in MainApp are removed - the composition root wires the coordinator,
adapter and the (independent) Legacy import boundary exactly once.
2026-09-22 09:48:38 +08:00
Qiu Yuzhou ea801d5f38 feat(catalog): remove node enable state
Migrate legacy enabled fields to v3 without preserving their semantics.
Keep recoverable invalid imports visible and filter them during activation.
2026-09-22 08:40:13 +08:00
Qiu Yuzhou fc571f2862 refactor(ng2): remove deprecated LaunchAgent plist file 2026-09-21 22:17:11 +08:00
Qiu Yuzhou 00fcd61a99 refactor(ng2): change bundle id to ShadowsocksX-NG2
Distinct id from Legacy (com.qiuyuzhou.ShadowsocksX-NG) lets NG2 own
~/Library/Application Support/ShadowsocksX-NG2/ directly; the v2/
subdir prefix is removed from all runtime paths.

- app/agent/tests targets + LaunchAgent plist renamed accordingly
- keychain service, queue labels, and Vendor signIdentifiers follow
  the new bundle id; embedded helpers re-sign at build time
- Legacy handoff/import constants keep pointing at the old id

Migration: dev data under ShadowsocksX-NG/v2/ is not carried over
(fresh catalog/activation); old LaunchAgent registration and old
keychain entries must be cleaned up manually.
2026-09-21 20:33:37 +08:00
Qiu Yuzhou c03db6c04a fix(ng2): allow handoff without Legacy jobs
Enable confirmation when no Legacy launchd actions remain, since
handoff still performs proxy cleanup, port checks, and 2.0 startup.

Refs #37
2026-09-21 15:35:38 +08:00
Qiu Yuzhou f16feb5f0c fix(ng2): open settings from status menu
Use an explicit settings window because the menu bar app has no application menu.

Refs #33
2026-09-21 15:17:21 +08:00
Qiu Yuzhou 7bfb90ef5c docs(ng2): reorganize development instructions 2026-09-21 14:42:58 +08:00
Qiu Yuzhou 62560c2232 fix(style): align SwiftLint with SwiftFormat 2026-09-21 14:17:21 +08:00
Qiu Yuzhou c745c323cd feat(ng2): add Taskfile for build and development tasks 2026-09-21 14:07:57 +08:00
Qiu Yuzhou 8d1cdf27d1 feat(ng2): Legacy 交接第二阶段(#37)
与导入分离的「切换到 2.0」确认流程(spec #21 D12):

- Domain/LegacyHandoff:硬编码白名单三个 Legacy label(.local/.http/.kcptun),
  bootout 按 service target(覆盖 plist 缺失错位形态),print 退出码验证
  (0/113),`launchctl kill SIGTERM` 有文档后备,绝不泛匹配、不 pkill;
  残留 plist(含 KeepAlive 形态)读内容判活跃性后 disable,阻止下次登录复活;
  系统代理按特征值判定归属(Legacy 自身 off 模式的判定镜像:本地 PAC URL
  http://localhost:<port>/proxy.pac、SOCKS/HTTP 地址端口),仅清理归属为
  Legacy 的服务,未知所有者点名保留;端口释放门禁用无复用选项的 bind 探测
  (Legacy ss-local 带 --reuse-port),未释放不启动 2.0;Legacy 数据零删除。
- App 层:SystemConfigurationLegacyProxyCleaner(授权在最前、失败零影响、
  事务回滚);WorkspaceLegacyAppController(共享 bundle id 需排除自身进程);
  LegacyHandoffSheet 确认/进度/报告呈现,含旧登录项人工指引与残留提示;
  主窗口工具栏入口 + 导入完成后「切换到 2.0」入口;交接成功经正常启停入口
  启动 2.0(健康门禁走 #29 路径)。
- bootout 实弹验证(Further Notes #5)闭环:docs/research/
  legacy-handoff-bootout-live-fire.md——bootout 未加载 label 退出码为 3
  (非 print 的 113),KeepAlive 残留 kill 后复活、bootout 后不再加载,
  结论已回写产品代码与测试。
2026-09-21 12:49:49 +08:00
Qiu Yuzhou 64eb7ff97d Configure app icon asset catalog 2026-09-21 11:47:54 +08:00
Qiu Yuzhou 8ec4a57deb feat(ng2): import Legacy configuration (#36) 2026-09-21 11:27:05 +08:00
Qiu Yuzhou 5e13c1716f feat(ng2): managed plugins end to end (#38)
- 受管插件静态事实表(v2ray-plugin v1.3.2,来源/许可证/版本/重签)与
  BundleManagedPluginProvider:受管集内且 bundle 内可执行文件在位才返回
  绝对路径;与 Vendor 清单双向锚定(D6/D10)
- 服务器编辑器插件区:受管选择器(无 + 受管列表),选中受管项才显示
  供应链事实与参数输入;集外引用显式「本版本未提供」并原样保留
- updateServer 插件落盘语义:「无」整体清除、参数写删钥匙串、集外不漂移
- wrapper 监听建立判定:3 秒未建立本地监听记 error 日志,监管继续(D10)
- 诊断导出新增受管插件清单(名称/版本/提供状态,无参数)
- 功能级兼容实测记录(docs/research/plugin-compat-record.md)与端到端
  冒烟:契约插件路径 → sslocal 拉起 → v2ray-plugin 进程建立 → 停止链
2026-09-21 10:38:30 +08:00
Qiu Yuzhou 2531eb35fb feat(ng2): add settings page and preferences (#33) 2026-09-21 08:54:12 +08:00
Qiu Yuzhou c3a9f62216 feat(ng2): menu bar quick actions and global shortcuts (#31)
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.
2026-09-21 07:39:22 +08:00
Qiu Yuzhou e683fe99b1 feat(ng2): port semantics and conflict handling (#30)
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.
2026-09-21 06:57:23 +08:00
Qiu Yuzhou a88e96c1e8 docs: subscription extension fallback semantics in CONTEXT.md (#35)
把「环」从刷新失败清单移出:私有扩展(含环在内的任何无效)按子票 #4
决议回退标准扁平列表、刷新本身按成功处理,与实现一致。
2026-09-21 06:22:52 +08:00
Qiu Yuzhou 0ecca53a20 feat(ng2): subscription fetch, snapshot semantics and UI (#35)
SIP-008 v1 + x_shadowsocksx_ng extension parsing with flat fallback;
HTTPS/Content-Type gated fetch seam; atomic snapshot commits carrying
only the local enabled overlay; URL edit keeps identity; recursive
delete clears source, fixed group, members and credentials; subscription
cards pane and menu-bar update-all wiring.
2026-09-21 06:15:52 +08:00
Qiu Yuzhou 72f9a45a74 feat(ng2): add system proxy modes and health gate (#29) 2026-09-20 23:31:33 +08:00
Qiu Yuzhou a6825aaafa feat(ng2): diagnostics log viewer and redacted export (#34)
主窗口诊断区(spec #21 D5/D11):

- RuntimeLog 增加事件接收缝,GUI 侧接入 RuntimeEventStore 内存环形缓冲
  (容量 500),wrapper 侧不变(stderr → agent.log 收敛)
- 主窗口侧栏新增「服务器/诊断」分区切换;诊断区日志查看器双源:GUI 事件
  实时呈现 + agent.log 尾部(1s 轮询),均可复制
- DiagnosticReportBuilder 显式触发的脱敏诊断导出:只含状态、存在性、权限、
  大小/时间、数量与脱敏元数据;不读 Keychain 与契约/目录内容;原始错误
  detail 不入导出,家目录前缀改写为「~」;服务器地址与备注不进入任何输出
- 投毒夹具测试验证导出不含任何敏感类目(密码/插件参数/地址/备注/token/JSON)

Closes #34
2026-09-20 22:41:28 +08:00
Qiu Yuzhou 8578de0ba4 feat(ng2): add PAC runtime and listen scope (#28) 2026-09-20 22:26:45 +08:00
Qiu Yuzhou 60a31b5df3 feat(ng2): main window server tree, ss:// codec and QR share/import (#32)
主窗口服务器分区(D11,issue #32):NavigationSplitView 分组树(订阅子树
只读、仅启用开关;行内 checkbox;右键激活/启停/重命名/新建分组/移动/删除,
非空手动组二次确认;拖拽移动,跨来源拒绝;空组保留可编辑)、服务器详情
表单(插件区只读展示「本版本未提供」状态)、分组详情。添加三入口(剪贴板
ss://、导入 URL、二维码图片识别:文件选择 + 拖图入窗)共用批量导入落点,
每次新建身份不去重;分享区二维码弹窗 + 复制 ss://。SsUri 按 SIP002 编解码
(含 legacy base64 兼容、SIP022 明文 userinfo、IPv6、插件 name;opts 逐字节
同构),二维码走 CoreImage 生成 + Vision 识别。目录提交后接 postCommit 钩
子,代理运行时立即重展开(#27 catalogDidCommit)。
2026-09-20 21:37:38 +08:00
Qiu Yuzhou 6bfd3c0d35 feat(ng2): proxy runtime LaunchAgent, wrapper and sslocal lifecycle (#27)
GUI → LaunchAgent → wrapper → sslocal full chain (spec #21 D2/D5):

- ShadowsocksX-NG2Agent: Swift BundleProgram tool target embedded at
  Contents/MacOS, supervised by launchd via SMAppService agent plist
  (Contents/Library/LaunchAgents, bundle-relative ProgramArguments,
  KeepAlive={SuccessfulExit:false}). Wrapper reads the cross-process
  contract v2/sslocal-active.json, spawns sslocal -c <absolute path>
  and supervises it: SIGTERM chain stop, SIGUSR1 forward for
  server-only changes vs graceful restart on listen fingerprint
  changes, non-zero exit on unexpected child loss for KeepAlive
  replay, invalid/missing contract → clean exit with plain unlink.
- Runtime file protocol: RuntimeFileStore reuses AtomicFileWriter
  (0700 dir self-heal, 0600 temp at creation, atomic replace);
  explicit-stop cleanup unlinks contract, agent pid file and stale
  temporaries. Shared read-side validation via
  SslocalRuntimeDocument.decodeValidated so GUI and wrapper cannot
  drift. Wrapper pid file bridges SMAppService's missing pid.
- GUI: ProxyRuntimeController consumes ActivationStateMachine effects
  through pure ProxyRuntimePlan decision table (ordered actions,
  idempotent skip of identical contract); proxy toggle and launch
  failure presentation (naming endpoint:port) in the status menu;
  launch resync reconciles agent registration, wrapper liveness and
  on-disk contract; catalog commits re-expand immediately.
- Log sanitization baseline: closed RuntimeLogEvent enum plus Redactor,
  wrapper/sslocal output converged to a 0600 agent.log with RUST_LOG
  defaulting to warn.

Tests (126 total, all green): stub-sslocal driven wrapper lifecycle
(start/stop order, SIGTERM chain, crash replay, cleanup, reload
protocol), real sslocal smoke (SOCKS port binding + full SOCKS5
handshake), plan decision table, controller flows with fakes,
runtime file permissions/atomic replace, endpoint probe, redaction.

Manual release-gate items (real launchd/SMAppService): agent
registration approval flow, GUI-quit persistence, bootout behaviors.

Closes #27
2026-09-20 20:26:54 +08:00
Qiu Yuzhou 9439e597e2 feat(ng2): activation semantics and runtime config derivation (#26)
激活状态机与派生层(spec #21 D3 激活族 + D5 派生):

- ActivationStateMachine:持久化活动目标(服务器或分组);激活原子成功
  或点名失败(保留原目标与运行状态);目录提交后立即重展开,失效即清除
  并发出停止意图(删除/禁用/变空/无效叶子各路径,无静默回退)
- 组激活按显式子序递归展开有效启用叶子;组目标保持组 UUID
- SslocalRuntimeDocument:完整 sslocal JSON 契约文档,凭据派生时解析,
  插件字段无插件时整体省略;ManagedPluginProviding 缝按「未提供」参与
  无效判定(真实受管集 #38 接通)
- ActivationStateFileStore:activation.json 持久化(0700/0600、原子替换,
  损坏按安全侧恢复为无活动目标);与 CatalogFileStore 共享 AtomicFileWriter
2026-09-20 18:50:58 +08:00
Qiu Yuzhou e8eb22c63d fix(ng2): bump build number above legacy 1.x
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.
2026-09-20 18:05:10 +08:00
Qiu Yuzhou 0cf28c97fe feat(ng2): config catalog domain core with credential refs (#25)
配置目录领域核心(spec #21 D3/D5,票 #25):

- Domain/ 新增配置目录树:单父、显子序、无环;手动/订阅来源严格分离;
  有效启用 = 节点及其全部祖先启用;手动节点携带子树移动与重排;
  非空手动组递归删除(返回被删条目供 Keychain 清理);空组持久保留;
  非法操作(跨来源、身份复用即共享父、成环、订阅节点结构改动、
  订阅服务器直挂根)全部带明确原因拒绝且状态不动。
- 凭据引用:密码/插件参数只在 Keychain 存权威副本,配置树只持
  CredentialReference;KeychainCredentialStore 写读一致、覆盖写、幂等删。
- CatalogFileStore:v2/catalog.json 目录 0700/文件 0600,临时文件原子替换;
  缺失 → 空目录,损坏/版本未知/结构不一致(悬空、共享父、成环含根外孤环、
  不可达)→ 命名明确的 corrupt,结构校验收敛在
  ConfigurationCatalog.validated 工厂。
- 测试 43 项覆盖全部验收项;project.yml 增加 Domain/ 源码目录。
- .swiftlint.yml 关闭 trailing_comma(与 .swift-format 尾逗号基线冲突,
  触发案例见文件内注释),README/AGENTS.md 同步 Domain/ 与工具说明。
2026-09-20 15:22:09 +08:00
Qiu Yuzhou 1b8b1f0767 docs(ng2): move style tool setup from AGENTS.md to README
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.
2026-09-20 14:36:35 +08:00
Qiu Yuzhou a20df3001f feat(ng2): external binary supply chain and packaging gate (#24)
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).
2026-09-20 14:27:21 +08:00
Qiu Yuzhou 635d22378e feat(ng2): add swift format + SwiftLint pre-commit gate (#23)
- 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)
2026-09-20 13:45:48 +08:00
Qiu Yuzhou 3f052e403f feat(ng2): add 2.0 project skeleton and signing baseline (#22)
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
2026-09-20 09:00:29 +08:00
Qiu Yuzhou 40bb5c9638 docs(domain): add managed plugin and plugin activation semantics
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.
2026-09-20 07:42:50 +08:00
Qiu Yuzhou 252b1a631a docs(research): add Wayfinder Issue 7 — Legacy configuration migration and legacy feature boundaries audit 2026-09-20 07:25:24 +08:00
Qiu Yuzhou 1a4b96fe83 docs(research): wayfinder issue 18 — SIP003 plugin distribution and verification boundary 2026-09-20 07:19:05 +08:00
Qiu Yuzhou 5acd4f1256 docs(research): wayfinder issue 17 — legacy runtime safe handoff APIs 2026-09-20 07:14:52 +08:00
Qiu Yuzhou 6218944b29 docs(research): wayfinder issue 16 — app firewall × non-loopback listen
实测结论(macOS 27.0,HITL 确认):回环零交互;launchd 语境按二进制
归属,官方 sslocal(adhoc,linker-signed)主机地址态必弹裸名弹窗;
DevID 重签静默放行为首选缓解;应答按路径落库、升级不重弹;拒绝后
本机自连不可见,需 --getappblocked 检测与定向修复文案。原型在
research/firewall-nwlistener @ 94829fe。
2026-09-20 06:12:47 +08:00
Qiu Yuzhou 4f39b88366 docs(domain): define local endpoint port semantics 2026-09-20 05:35:44 +08:00
Qiu Yuzhou fef0daa7da docs(domain): define proxy runtime host semantics 2026-09-20 04:12:27 +08:00
Qiu Yuzhou 6b58925bbd docs: Add research for wayfinder issue 12 (PAC HTTP server) 2026-09-20 03:43:15 +08:00
Qiu Yuzhou 940fb603a6 docs(agents): require explicit --repo on gh (fork has upstream remote) 2026-09-20 03:42:53 +08:00
Qiu Yuzhou e3604e513c docs(domain): define listen scope 2026-09-20 03:36:16 +08:00
Qiu Yuzhou 43c56cdbe1 merge: PAC research into develop 2026-09-20 03:00:54 +08:00
Qiu Yuzhou d9adfdc31f docs: research PAC implementation options 2026-09-20 02:37:37 +08:00