13 Commits
Author SHA1 Message Date
Qiu Yuzhou 17c9f15928 fix(window): bring presented window reliably to front at launch
Keyboard-launcher launches (Raycast/Spotlight Enter) left the
LSUIElement app unforegrounded with a missing Dock icon until Mission
Control forced a refresh. Investigation across real-machine rounds
(recorded in the ADR-0017 supplements) pinned three cooperating causes:

- The launch activation retry never started at launch: the workspace
  window's participation events (anchor attach / occlusion / key) could
  all miss the launch moment when content installed before the window
  became visible and the visibility notification fired before the
  anchor attached. A deferred visibility rescan plus re-armable chain
  (until truly settled) close this gap.
- NSApp.isActive can report an activation illusion while the menu bar
  still belongs to the previous frontmost app, so the settle check now
  requires both isActive and menu bar ownership.
- A same-turn accessory->regular bounce is coalesced away by the
  system; forced activation is a three-hop sequence with real settle
  delays (accessory -> 0.1s -> regular -> 0.15s -> activate), which
  re-registers the app with WindowServer/Dock and reclaims the menu
  bar. Each acting attempt also re-asserts makeKeyAndOrderFront and
  orderFrontRegardless as a visible-layer fallback.

Diagnostics: launchActivationRetry and windowAnchorAttached events
(unified-log category "window") record per-attempt facts (activation,
local policy, frontmost app, menu bar owner, space, window visibility);
user-environment facts stay out of shared diagnostic reports.
2026-10-22 03:24:14 +08:00
Qiu Yuzhou 94ef128db8 feat(system-proxy): emit privileged helper events to unified log
The root system-proxy helper logged nothing and launchd discards its
stdout/stderr, leaving helper launches, connection refusals, GUI-side
timeouts and root-side failures invisible. Share the minimal unified-log
emission unit (SystemLog) across GUI, wrapper and helper, and add a
dedicated closed helper event enum (lifecycle minimum: listener ready,
connection accepted/rejected with peer pid, typed apply/clear results)
with ADR-0045 privacy splitting. The emission seam is injected at the
helper engine and listener for test doubles. Helper events are
Console-only: no stderr, no agent.log, no diagnostic view or report
surface (ADR-0047).
2026-10-20 15:59:38 +08:00
Qiu Yuzhou 1d85e86b8e feat(diagnostics): unify log lines into one filtered view
Collapse the four definitions of "one log line" into LogLine (timestamp,
level, source, text) with a single renderer and parser. agent.log lines
now carry the uniform prefix, absorbing the ssxng: event marker into the
source column; legacy lines degrade to raw display without rewriting.
Level detection moves into the row model with a classic three-level
taxonomy whose unified-log projection stays unchanged.

The diagnostics log view merges GUI events and the agent.log tail through
DiagnosticLogIntake into one time-ordered list with level and source
filters; the tail window logic moves into the intake and blank lines are
kept for raw fidelity. The report whitelist projection and unified-log
routing are unchanged.
2026-10-20 14:42:51 +08:00
Qiu Yuzhou 1541e97fb3 test(runtime): silence unified-log writes during test runs
Add the SSXNG_SYSTEM_LOG=0 test seam: RuntimeLog.emit and the sslocal
unified-log destination skip their os.Logger writes when it is set,
while stderr lines and the event sink are unaffected. Test execution
no longer floods the unified log store (a full validate run previously
recorded 795 entries under the shared subsystem, 743 from xctest and
52 from test-spawned agents).

The switch is injected by the schemes' test actions only (Run/Profile
keep system logging so debugging from Xcode still shows it), and set
explicitly in the fixtures that spawn the agent/sslocal processes,
including the fixture that strips inherited SSXNG_* path seams. The
main scheme is now declared explicitly to keep the variable out of the
Launch/Profile actions. Document the seam in ADR-0045.
2026-10-20 12:38:21 +08:00
Qiu Yuzhou b6817568f3 docs(adr): record unified log routing decision
Record ADR-0045: unified-log routing through the emission seam with
native os.Logger and no third-party logging library, the closed-enum
dispatch with public/private text split, and the sslocal output intake
as a second free-form stream that never enters RuntimeLogEvent. Point
the systemLogRoute comment at the ADR.
2026-10-20 12:24:34 +08:00
Qiu Yuzhou d099239e3e feat(agent): route sslocal output through a dual-destination intake
Collect line framing, password redaction and oversized-line discard in
one SslocalOutputIntake and dispatch redacted lines through a
destination seam: stderr (freopen'd into agent.log, raw capture kept
for ADR-0006 local viewing) and the unified log under category "sslocal",
reusing the shared subsystem.

Upstream free text is never routed through RuntimeLogEvent and is
marked private in the unified log as a whole (ADR-0014 warns default
upstream logs may contain server addresses). Levels derive from
whitespace-separated upstream level tokens: ERROR maps to .error,
WARN/WARNING maps to .default (unified logging has no warning level),
and anything else maps to .info so the unified-log surface persists
only detected problems while agent.log stays the persistent surface.

The intake lives in Domain/Runtime so the hostless test mirror compiles
it; unit tests drive raw chunks against fake destinations instead of
parsing agent.log text. The 1 MiB agent.log retention policy deliberately
stays on the file side shared with wrapper event lines.
2026-10-20 12:18:41 +08:00
Qiu Yuzhou ec09d79399 feat(runtime): route runtime events to the unified log
Emit every RuntimeLogEvent to os.Logger under a shared subsystem with
per-event category and level, so GUI and wrapper output can be filtered
in Console.app. Public text is split from private detail (free-form error
text and connectivity measurement content) on the closed enum, keeping
server addresses out of the public log surface. The stderr line and the
event sink stay unchanged. Add the system log glossary term.
2026-10-20 11:06:14 +08:00
Qiu Yuzhou e0db8b1e13 refactor(runtime): publish isolated supervision generations
Separate Agent supervision from sslocal input and preserve the latest intent after deployment failure. Persist failure barriers, serialize publication and retirement, and verify reload and single-instance behavior with real processes.

Refs #83
2026-10-19 03:00:33 +08:00
Qiu Yuzhou 6cbef4e57a refactor(connectivity): store test URL in user defaults 2026-10-18 08:31:13 +08:00
Qiu Yuzhou 27b91d60e1 refactor(settings): drop listen-settings ghost path and error-type mirrors 2026-10-17 14:34:57 +08:00
Qiu Yuzhou 297fc30c41 feat(connectivity): measure warmed HTTP latency phases 2026-10-15 17:39:13 +08:00
Qiu Yuzhou c49d605a5b chore(ng2): remove fork issue references from comments 2026-10-13 00:38:06 +08:00
Qiu Yuzhou 856d6b4272 refactor(domain): 按主题重组 Domain/ 源码目录
Domain/ 根目录原有 62 个平铺源文件,无法从目录读出主题划分。

按「目录即主题」重组为 11 个目录(Rules/Custom 为嵌套子目录):Catalog /
Subscription / Rules / Runtime / Activation / Settings / SystemProxy /
Plugin / Credentials / LegacyImport / Diagnostics。纯移动:类型名、模块名
与 import 均未改动,Domain/ 根下不再有散落文件。目录口径取自
GLOSSARY.md 的章节划分(配置与订阅、代理规则、代理控制与网络、设置、
凭据与诊断),而非新造分类。

配套改动:

- project.yml:wrapper 与 helper 两个 target 按文件引用的 15 条显式路径
  随目录改名,并补注释固定这一约定——这 15 条指向不存在的文件时,
  xcodegen generate 以 "missing source directory" 直接失败(实测,不静默)。
- SkeletonTests 新增 DomainLayoutTests:断言 Domain/ 根下无平铺 .swift、
  树下只有 .swift。后者防的是与 App/ 同源的坑——Domain/ 整目录是 app 与
  Core 的 source path,任何非源码文件都会被 XcodeGen 收进 Resources 阶段
  并封进签名后的 bundle。
- README 工程结构说明同步;docs/design 与 docs/research 属历史文档不改。

验证:xcodegen generate 后 app 164 / Core 163 源文件数与整理前一致;Agent
恰好 9 个、Helper 恰好 6 个 Domain 文件(无缺失无多出);app 与 Core 各覆盖
全部 62 个。clean build 0 error;task test 1024 用例全通过(整理前 1022,
+2 为新增守卫);task format 未改写任何被移动文件(证明纯移动);task lint
与整理前同为 21 条内容型 warning;packaging-gate.sh ALL CHECKS PASSED。

布局守卫已做变异验证:临时投放松散 .swift 与非 .swift 文件时两个用例均
失败并点名违规文件,清理后复验为绿。
2026-10-05 20:13:35 +08:00