Beacon Solution / Project Directory¶
Companion to RFC-001. This document is based on the actual current repository structure (synchronized 2026-10-09). Beacon code can only be built and run on Windows (WinUI 3, CI
windows-latest); a Linux development environment can build and run the 4 test projects as a local gate.
1. Solution Overview¶
Beacon/
├── Beacon.sln
├── Directory.Build.props # 公共编译设置(nullable、langversion、invariants)
├── Directory.Packages.props # Central Package Management(统一版本)
├── global.json # 钉 SDK 10.0.100(rollForward latestFeature)
├── .editorconfig
├── .github/workflows/ # ci.yml(构建+测试+Codecov)/ daily-build.yml(nightly)/ docs.yml(Pages)
├── docs/ # 任务书 / RFC / Issue 列表 / 定位 / 审计 / 验收记录
├── packaging/ # beacon.iss:Inno Setup 安装包定义(daily-build 产出 setup.exe)
├── src/
│ ├── Beacon.App/ # WinUI 3 壳(唯一 exe,代码建 UI 为主)
│ ├── Beacon.Core/ # 领域模型 + 抽象 + 服务(无 UI 依赖)
│ ├── Beacon.Connections/ # 连接与 Widget Provider(17 类:GitHub / Jenkins / 本机 / Herald / HTTP / 智谱 / 方舟 / Claude / Kimi / Moonshot / DeepSeek / MiMo / Codex / Copilot / OpenCode / 百炼 / 商汤)
│ ├── Beacon.Actions/ # Action 执行器
│ └── Beacon.Storage/ # JSON 配置 / 缓存 / DPAPI Secrets / 导入导出
└── tests/
├── Beacon.Core.Tests/
├── Beacon.Connections.Tests/
├── Beacon.Storage.Tests/
└── Beacon.Actions.Tests/
2. Project Dependency Rules¶
Beacon.App ──────► Beacon.Core ◄────── Beacon.Connections
│ ▲ Beacon.Actions
│ │ Beacon.Storage
└──────────────────┴──────────────────┘(实现 Core 抽象,被 App 组合)
tests/* ──► 对应被测项目(+ Beacon.Core 接口)
Hard rules:
Beacon.Corereferences no projects (only BCL +Microsoft.Extensions.Logging.Abstractions) — ensures UI and Provider are replaceable.- Connections / Actions / Storage depend only on Core (implementing its interfaces) and are independent of each other.
Beacon.Appis the only executable project, responsible for DI assembly: registers Providers/Executors/Stores intoMicrosoft.Extensions.DependencyInjection(App.BuildServices+BeaconRuntime).- In the Phase 2 plugin transition, split the Providers inside Connections into separate assemblies, keeping the interfaces unchanged.
3. Contents of Each Project¶
3.1 src/Beacon.Core (class library)¶
Beacon.Core/
├── Models/ # 13 文件
│ ├── Severity.cs # Info/Success/Warning/Error/Critical(+ Offline 展示态)
│ ├── LifecycleState.cs # Queued/Running/…/Unknown
│ ├── ConnectionConfig.cs ConnectionHealthState.cs WidgetConfig.cs WidgetTypeDescriptor.cs
│ ├── WidgetDisplayPolicy.cs # 数值类悬浮总闸(FloatingOptIn × NumericFloatingEnabled,两 L0 形态共用)
│ ├── WidgetState.cs # widgetId/widgetType/connectionId/severity/summary/payload/…
│ ├── ActionModels.cs # ActionConfig / ActionResult(合并文件)
│ ├── NotificationModels.cs # NotificationRule / NotificationRecord / Delivery(合并文件)
│ ├── RefreshTiers.cs # 7 级刷新策略(pr/ci/machine/agent/workflow/static/default)
│ ├── AppConfig.cs # 全局设置 + PinTile/PinsConfig
│ └── PinLayout.cs # monitor/anchor/offsetDips/collapsed + floatingX/Y(悬浮框位置)
├── Abstractions/ # 8 文件
│ ├── IConnectionProvider.cs # IConnectionProvider + IWidgetProvider + IWidgetProviderResolver(合并文件)
│ ├── IActionExecutor.cs ISecretStore.cs IConfigurationStore.cs ICacheStore.cs
│ ├── IClock.cs # 注入时钟,供退避/冷却单测
│ ├── IEventBus.cs
│ └── INotificationSink.cs # 通知出口(App 侧 Toast/声音/托盘着色实现)+ 记录落盘抽象 INotificationRecordStore
├── Services/ # 20 文件
│ ├── EventBus.cs # 线程安全的进程内发布/订阅
│ ├── RefreshScheduler.cs # (connection,tier,间隔覆盖) 合并轮询 + 抖动 + 退避
│ ├── StatusAggregator.cs # WidgetState* → 总体 Severity + 计数
│ ├── NotificationEngine.cs # 规则求值 + 冷却去重 + 默认规则
│ ├── ActionRunner.cs # 确认策略 + 超时 + 取消 + 可选重试(DSL retry 参数,默认 1 次)
│ ├── ActionVisibility.cs # 动作显隐纯函数(widgetType 逗号多值 + connection_id 限定)
│ ├── WidgetHost.cs TemplateRenderer.cs PaletteResolver.cs PinLayoutMath.cs
│ ├── SvgPathParser.cs # SVG path d → 中性几何(品牌图标渲染前置层,纯函数供单测)
│ ├── BrandIcons.cs # Simple Icons CC0 品牌 path 字典 + 连接类型别名归一(纯字符串零依赖,供单测;未收录由 App 字形兜底)
│ ├── WidgetValueHint.cs # 悬浮 tile 数值位短文本(各家额度源 payload 键 → 主数值映射 + 多窗口额度「NN%/窗」拼接,纯函数供单测)
│ ├── DebugInjection.cs # debug 注入面(BEACON_DEBUG_SEVERITY=critical → 刷新成功态改判 Critical/Failed;环境变量门控、缺省零行为,仅 CI 场景 V 与装机演练用,不进用户文档)
│ ├── WidgetTypeNames.cs # 组件类型 → 短显示名(tile 标签/L2 分组 chip 共用,纯函数供单测)
│ ├── QuickPanelSections.cs # L2 面板三分区判定(Warning+/过期/断连 → NEEDS ATTENTION,纯函数供单测)
│ ├── DpiLayoutMath.cs # DIP↔物理像素唯一换算口径(AppWindow 只认物理像素)
│ ├── ContrastMath.cs # WCAG 2.x 对比度数学(纯函数,Linux 门禁可测)
│ ├── HighContrastPalette.cs # 高对比调色板(WCAG AA 4.5:1,配对经 Core.Tests 断言)
│ └── UpdateCheck.cs # 版本解析/比较/判定 + GitHub tag_name 提取(纯函数,Linux 门禁可测;App 侧只做网络与 UI)
├── Events/
│ └── Events.cs # WidgetStateChanged / AggregateStatusChanged 等事件
└── Json/
└── BeaconJson.cs # JsonSerializerOptions(camelCase + 枚举字符串)
3.2 src/Beacon.Connections (class library, flat files with no subdirectories)¶
Beacon.Connections/ # 35 文件
├── TileSizing.cs # 全类型 tile 宽度字宽预算(逐列最坏文本:标签/数值/读数 + 固定件 + 间距,下限 168;纯函数供单测,2026-10-12 二修)
├── GitHub 6 文件
│ ├── GitHubConnectionProvider.cs # PAT 认证、连接测试、rate-limit 感知
│ ├── GitHubApiClient.cs # 手写 REST 客户端(不引 Octokit)+ ETag 条件请求 + 限额感知
│ ├── GitHubWidgetDescriptors.cs # Widget 类型元数据注册表(type: github.pull_requests / github.actions.runs)
│ ├── GitHubPullRequestsProvider.cs # type: github.pull_requests
│ ├── GitHubActionsProvider.cs # type: github.actions.runs
│ └── GitHubWorkflowExecutors.cs # gh.workflow_dispatch/rerun/cancel 执行器
├── Jenkins 1 文件
│ └── JenkinsBuildProvider.cs # type: jenkins.build(开源标准 JSON API,color 判级)+ JenkinsConnectionProvider(同文件)
├── Machine 4 文件(本机数据,零凭据零网络)
│ ├── MachineNetProvider.cs # type: machine.net(IP/↑↓速率/累计流量,差分算速率)+ MachineWidgetDescriptors + MachineConnectionProvider(同文件)
│ ├── MachineLocalProvider.cs # type: machine.local(CPU/内存/磁盘,CPU 差分同速率口径;Linux /proc + Windows API 注入抽象)
│ ├── MachineShowOptions.cs # config["show"] 可选展示项解析(缺省全选/未知键 fail-loud;宽度推算在 TileSizing)
│ └── GitWorkspaceProvider.cs # type: machine.git(本地 Git 工作区 ↑↓·改·stash,git CLI 只读)
├── Herald 1 文件(用户自有项目 cuihairu/herald:统一订阅与投递中枢)
│ └── HeraldProvider.cs # type: herald.incidents(事件台账 open 亮黄/critical 亮红)+ herald.feed(RSS 未读基线,token 走 DPAPI)+ herald.deliveries(投递失败 failed 即黄)+ HeraldConnectionProvider(同文件)
├── HTTP 7 文件(Generic HTTP 接入)
│ ├── HttpConnectionProvider.cs # 连接测试(支持 auth_header/auth_prefix 覆盖)
│ ├── HttpEndpoint.cs # 端点请求与凭据装配
│ ├── HttpJsonPath.cs # $.a.b[0] 点路径提取
│ ├── HttpQuotaProvider.cs # type: http.quota(任意配额 JSON 字段映射 → 数值卡 + 进度条)
│ ├── HttpStatusProvider.cs # type: http.status(点路径 + 状态词表 → Severity)
│ └── ProviderDsl.cs # YAML provider DSL(批3-补42):dsl_path 声明层(mapping 数据提取缺省 + actions 带 retry)+ YamlLite 极小解析器
├── BigModel 2 文件
│ ├── BigModelConnectionProvider.cs # 裸 Key 认证(Authorization 不带 Bearer)
│ └── BigModelUsageProvider.cs # type: bigmodel.usage(quota/limit 三窗口归一化)
├── Ark 2 文件
│ ├── ArkConnectionProvider.cs # V4 签名连接测试(失败按 4xx/5xx 分级 Degraded/Offline)
│ └── ArkUsageProvider.cs # type: ark.usage(GetCodingPlanUsage 三窗口百分比;AK/SK 只进 DPAPI)
├── Claude 2 文件
│ ├── ClaudeConnectionProvider.cs # 零网络连接测试(会话目录存在即 Healthy)
│ └── ClaudeUsageProvider.cs # type: claude.usage(本机 JSONL 聚合,零凭据)
├── Kimi 1 文件
│ └── KimiCodingUsageProvider.cs # type: kimi.coding(5h/周套餐余量)+ KimiConnectionProvider(同文件)
├── DeepSeek 1 文件
│ └── DeepSeekBalanceProvider.cs # type: deepseek.balance(开放平台余额)+ DeepSeekConnectionProvider(同文件)
├── MiMo 1 文件
│ └── MiMoUsageProvider.cs # type: mimo.usage(官方未开放用量口→模型目录真数据)+ MiMoConnectionProvider(同文件)
├── Codex 1 文件
│ └── CodexUsageProvider.cs # type: codex.usage(本机 rollout 会话统计,source=local 如实标注)+ CodexConnectionProvider(同文件)
├── Copilot 1 文件
│ └── CopilotUsageProvider.cs # type: copilot.usage(官方扩展同款配额端点直连,quota_snapshots 三槽)+ CopilotConnectionProvider(同文件)
├── OpenCode 1 文件
│ └── OpenCodeUsageProvider.cs # type: opencode.usage(官方 Console Budgets API 直连,micro-cents 金额)+ OpenCodeConnectionProvider(同文件)
├── Qwen 1 文件
│ └── QwenUsageProvider.cs # type: qwen.usage(百炼 Token Plan 四档探测:官方口→自定义→配额探针→模型目录兜底)+ QwenConnectionProvider(同文件)
├── Moonshot 1 文件
│ └── MoonshotBalanceProvider.cs # type: moonshot.balance(开放平台余额,区别于 Kimi For Coding 套餐)+ MoonshotConnectionProvider(同文件)
└── SenseNova 1 文件
└── SenseNovaUsageProvider.cs # type: sensenova.usage(控制台 Token Plan 积分池:多池 × 5h/7d 双窗,最差窗判级)+ SenseNovaWidgetDescriptors + SenseNovaConnectionProvider(同文件)
3.3 src/Beacon.Actions (class library)¶
Beacon.Actions/ # 5 文件
├── ActionVars.cs # 参数模板占位符替换({repo} 等)
├── OpenUrlExecutor.cs # open.url(系统默认浏览器)
├── HttpExecutor.cs # http(GET/POST + 头/体模板)
├── WebhookExecutor.cs # webhook(POST + HMAC-SHA256 签名头,密钥 credentialRef 只进 DPAPI、取不到即 fail closed)
└── LocalCommandExecutor.cs # local.command(powershell/cmd/exe,工作目录/Env/超时/捕获输出)
- The three executors
gh.workflow_dispatch / gh.workflow_rerun / gh.workflow_cancelare inBeacon.Connections/GitHubWorkflowExecutors.cs.
3.4 src/Beacon.Storage (class library)¶
Beacon.Storage/ # 6 文件
├── JsonConfigurationStore.cs # config/connections/widgets/pins.json 原子写 + 备份
├── AppConfigFile.cs # config.json 快速读写(App 启动主题等早期读取)
├── JsonNotificationRecordStore.cs # notifications.json 通知记录 + 已读态(滚动保留跨重启)
├── JsonCacheStore.cs # cache\{connId}\states.json last-known-state
├── DpapiSecretStore.cs # DPAPI CurrentUser → secrets.bin(唯一默认实现)
└── ImportExport.cs # 打包导出(不含 secrets)/导入
Alternative (not implemented): Windows Credential Manager secret storage — same ISecretStore interface, code not landed.
3.5 src/Beacon.App (WinUI 3, packaging=None)¶
Beacon.App/
├── App.xaml / App.xaml.cs # 入口:单实例、全局异常兜底、DI 组装、窗口装配、退出清理
├── app.manifest / Assets/ # PerMonitorV2 DPI;图标与托盘 logo 掩膜(嵌入资源)
├── Infrastructure/
│ ├── MonitorService.cs # 显示器枚举/工作区/按像素定位(多屏)
│ ├── NativeMethods.cs # P/Invoke(NOTIFYICONDATA、窗口扩展样式、DPI、热键)
│ └── Win32MessageWindow.cs # 自驻留消息窗(托盘/热键/单实例事件回调)
├── Services/ # 15 文件
│ ├── BeaconRuntime.cs # 运行时装配:Provider 解析器、调度、聚合、启停联动
│ ├── UpdateCheckService.cs # 检查更新(B-806):GitHub releases/latest,10s 超时 + 进程内缓存 + 失败降级不抛异常
│ ├── TrayIconService.cs # Win32 Shell_NotifyIcon 自实现:菜单、按配置色着色、气泡
│ ├── ToastNotificationService.cs # Microsoft.Toolkit.Uwp.Notifications(Compat 激活路由、深链 L3)
│ ├── TopmostGuard.cs # 置顶哨兵(Watch 单窗 / WatchAll 动态窗集)
│ ├── HotkeyService.cs # RegisterHotKey,可配置(默认 Ctrl+Alt+B)
│ ├── StartupService.cs # HKCU Run 键开关
│ ├── SingleInstanceGuard.cs # Mutex + 命名事件(二次启动通知既有实例弹气泡)
│ ├── FileLoggerProvider.cs CrashLog.cs # beacon-YYYYMMDD.log / crash-*.log
│ ├── UiPalette.cs MotionEngine.cs ShellStateStore.cs UiDispatcher.cs
│ └── AppIcon.cs # 应用图标唯一来源(逐窗 AppWindow.SetIcon——unpackaged 任务栏图标坑)
└── Windows/ # 10 文件(8 .cs + 2 .xaml,UI 多为代码构建)
├── CapsuleWindow.xaml|cs # L1 聚合胶囊(独立置顶常驻窗,位置记忆;右键直达设置)
├── QuickPanelWindow.xaml|cs # L2 快捷面板(可激活,ESC 关;通知中心/组件列表)
├── PinnedHostWindow.cs # ★ L0 宿主面板形态(默认):每显示器一窗,代码建 UI,
│ # Topmost+NoActivate+空白点击穿透;含 PinTile 控件
├── FloatingTileWindow.cs # ★ L0 独立悬浮框形态(pinDisplayMode=floating):
│ # 每钉选组件一窗,拖放位置按组件持久化(FloatingX/Y)
├── BrandIconFactory.cs # 品牌 path → Path(Stretch=Uniform)(设置目录/悬浮 tile 共用,
│ # 空几何/渲染失败退 null 让调用方字形兜底)
├── DetailWindow.cs # L3 详情 + 全部 Action(代码建 UI)
├── ThemeColors.cs # 主题色桥:Core 高对比调色板 → WinUI 画刷(配对断言见 ContrastMathTests)
└── SettingsWindow.cs # B-801/802/805:PowerToys 形态配置中心(模块目录+启停+连接/组件 CRUD,
# 悬浮形态二选一、导入导出、通知规则;代码建 UI)
Note: no Controls/, ViewModels/, Themes/, Notifications/ directories — status lights/PinTile etc. are composed as code classes (PinTile is inside PinnedHostWindow.cs), no XAML resource dictionaries; Toast is in Services/.
3.6 tests/¶
xUnit; Beacon.Core.Tests (aggregation/scheduling/backoff/rules/notification engine/ActionRunner, clock injection; SvgPathParser, full parseability and aliases of the BrandIcons dictionary, WidgetValueHint numeric mapping), Beacon.Connections.Tests (fake HttpMessageHandler + API fixtures + ETag branches, assembly serialization to avoid shared client cache races), Beacon.Storage.Tests (round-trip/atomic write/DPAPI, requires Windows environment), Beacon.Actions.Tests (open.url/local.command/http/webhook executors, Windows-only test cases OS-gated). All wired into coverlet.collector (CI reports to Codecov). Currently 4 projects with a total of 1057 tests (Connections 652 / Core 347 / Actions 27 / Storage 31), i.e. the local gate. The Core side also covers QuickPanelSections three-section classification, ContrastMath/HighContrastPalette contrast pairings, WidgetTypeNames short-name mapping, PinLayoutMath/DpiLayoutMath conversion and clamping, and UpdateCheck version parsing and SemVer comparison (v prefix/build metadata/pre-release rules/rate-limit degraded body).
4. Key NuGet Packages (unified versions in Directory.Packages.props)¶
| Package | Used for |
|---|---|
Microsoft.WindowsAppSDK |
WinUI 3 runtime |
Microsoft.Windows.SDK.BuildTools |
Win32 interop (NoActivate/hotkeys, etc.) |
CommunityToolkit.Mvvm |
Referenced in App project but currently unused (UI is code-behind, see §6) |
| Tray | No third-party library; Win32 Shell_NotifyIcon implemented in-house (TrayIconService) |
Microsoft.Toolkit.Uwp.Notifications |
Toast (unpackaged AUMID self-healing and activation routing) |
System.Drawing.Common |
Tray icon drawn at runtime with configured color (GDI+ bitmap → HICON, B-706) |
| GitHub API | Hand-written REST client (ETag/rate-limit controllable, B-301 decision, no Octokit) |
System.Security.Cryptography.ProtectedData |
DPAPI secret storage |
Microsoft.Extensions.Hosting / .DependencyInjection / .Logging |
DI/logging |
xunit / NSubstitute / coverlet.collector |
Testing and coverage |
(Versions centralized in Directory.Packages.props; the table excludes unreferenced packages.)
5. Scaffolding Commands on Windows (historical archive, project already built)¶
The following are the commands actually used when initially creating the repository, retained for reference; the current structure and files are authoritative as in §1/§3.
dotnet new sln -n Beacon
dotnet new classlib -o src/Beacon.Core -f net10.0
dotnet new classlib -o src/Beacon.Connections -f net10.0
dotnet new classlib -o src/Beacon.Actions -f net10.0
dotnet new classlib -o src/Beacon.Storage -f net10.0
dotnet new winui -o src/Beacon.App # 模板可用缺失时:手建 csproj(WindowsAppSDKSelfContained,打包=None)
dotnet new xunit -o tests/Beacon.Core.Tests
dotnet new xunit -o tests/Beacon.Connections.Tests
dotnet new xunit -o tests/Beacon.Storage.Tests
dotnet new xunit -o tests/Beacon.Actions.Tests
dotnet sln add (git ls-files "**/*.csproj")
Note (.NET 10 LTS, RFC §16 decision 8): the four class libraries target net10.0 (DPAPI via the System.Security.Cryptography.ProtectedData package, no Windows-specific TFM); Beacon.App targets net10.0-windows10.0.19041.0, TargetPlatformMinVersion=10.0.17763.0 (WinUI 3 / Windows App SDK). The SDK version is pinned to 10.0.100 by the root global.json (rollForward latestFeature).
6. Coding Conventions¶
nullable enable, file-scoped namespace, C# 12.- UI is primarily code-built + code-behind (WinUI
Windowsubclasses directly compose controls), state comes from event bus subscriptions (BeaconRuntime/Subscribeinside windows); theCommunityToolkit.Mvvmpackage is referenced but currently unused (no ViewModel layer). - All time-related logic is injected via
IClock. - Configuration JSON uses
System.Text.Json:BeaconJsoncentralizesJsonSerializerOptions(camelCase properties + enum strings), not source-gen. - Logging via
ILogger, Secrets never go into logs (RFC-001 §13).