From fd43e5042aee7f750e7f7ca60cf2c56cebb153a2 Mon Sep 17 00:00:00 2001 From: hepinga Date: Sun, 19 Jul 2026 20:38:19 +0800 Subject: [PATCH] chore: remove internal repository materials --- .github/PULL_REQUEST_TEMPLATE.md | 2 + .gitignore | 6 + AGENTS.md | 34 -- CHANGELOG.md | 3 +- CLAUDE.md | 34 -- CONTRIBUTING.md | 4 + README.md | 2 +- README.zh-CN.md | 2 +- ...15\344\275\234\346\270\205\345\215\225.md" | 82 ---- ...24\344\270\216\346\226\271\346\241\210.md" | 182 --------- docs/PRD.html | 333 --------------- docs/PRD.md | 76 ---- ...63\345\217\260\350\256\276\350\256\241.md" | 266 ------------ ...21\345\270\203\346\214\207\345\215\227.md" | 140 ------- .../index.html" | 326 --------------- ...\347\240\224\346\212\245\345\221\212.html" | 382 ------------------ ...75\345\212\240\351\234\200\346\261\202.md" | 41 -- release-notes/0.10.0.md | 24 -- release-notes/0.8.99.md | 7 - scripts/check-release-prerequisites.sh | 2 +- scripts/release.sh | 2 +- tests/MacPulseTests/CoreRegressionTests.swift | 4 +- website/.gitignore | 3 + website/.openai/hosting.json | 5 - website/README.md | 3 +- website/tests/worker-api.test.ts | 6 +- website/tests/worker-lifecycle.test.ts | 6 +- website/vite.config.ts | 4 +- 28 files changed, 31 insertions(+), 1950 deletions(-) delete mode 100644 AGENTS.md delete mode 100644 CLAUDE.md delete mode 100644 "docs/Gatekeeper\346\223\215\344\275\234\346\270\205\345\215\225.md" delete mode 100644 "docs/GitHub\350\243\205\344\277\256\350\260\203\347\240\224\344\270\216\346\226\271\346\241\210.md" delete mode 100644 docs/PRD.html delete mode 100644 docs/PRD.md delete mode 100644 "docs/ZOPC\350\264\246\345\217\267\347\244\276\345\214\272\344\270\216\346\234\215\345\212\241\345\271\263\345\217\260\350\256\276\350\256\241.md" delete mode 100644 "docs/\345\217\221\345\270\203\346\214\207\345\215\227.md" delete mode 100644 "docs/\347\240\224\347\251\266\345\272\223/index.html" delete mode 100644 "docs/\350\260\203\347\240\224\346\212\245\345\221\212.html" delete mode 100644 "docs/\350\277\275\345\212\240\351\234\200\346\261\202.md" delete mode 100644 release-notes/0.10.0.md delete mode 100644 release-notes/0.8.99.md delete mode 100644 website/.openai/hosting.json diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bd63cc0..8a88eb8 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -23,6 +23,8 @@ - [ ] Screenshots and logs contain no tokens, credentials, usernames, private paths, or conversation text. - [ ] 截图与日志不包含 token、凭证、用户名、私人路径或会话正文。 +- [ ] This PR contains no internal roadmap, private research, account/deployment identifier, maintainer runbook, or collaboration note. +- [ ] 本 PR 不包含内部路线图、私有调研、账号/部署标识、维护者手册或协作纪要。 - [ ] Cleanup/path changes preserve the documented safety invariants, or this PR does not touch them. - [ ] 清理/路径改动保持既有安全不变量,或本 PR 未涉及这些逻辑。 diff --git a/.gitignore b/.gitignore index 37d3a66..6c5db7d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,9 @@ dist/ # 本机协作纪要,不进入公开源码快照 会话纪要.md 交接文档-*.md + +# 维护者内部资料与本机 Agent 指令,不进入公开仓库 +AGENTS.md +CLAUDE.md +docs/private/ +release-notes/*.draft.md diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 1a0a1c8..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,34 +0,0 @@ -# MacPulse(Mac监控器) - -Swift 菜单栏系统监控 app:系统指标(CPU/内存/网络/磁盘/温度/风扇)+ AI token 用量与费用预估(解析 ~/.claude/projects 与 ~/.codex/sessions 的会话 JSONL)。 - -## 构建 - -- 只用 `./scripts/build.sh`(编译 + 打包 dist/MacPulse.app + ad-hoc 签名),不要直接裸跑 `swift build`。 -- 本机 CLT 损坏(两个旧版残留文件),build.sh 内置无 sudo workaround(`.clt-fix/`);永久修复方案见 README。2026-07 起本机已装 Xcode 26.6(xcode-select 指向 Xcode,SDK MacOSX26),workaround 段在 CLT 残留文件存在时仍会激活但无害。 -- 目标 macOS 14+,Swift 5 语言模式(tools-version 5.10)。 - -## 发布(官网分发,不上 MAS) - -- `./scripts/release.sh <版本> <递增构建号>`:构建 → Sparkle 嵌套签名 → Developer ID 签名(hardened runtime)→ notarytool 公证 → staple → DMG → 公证 DMG → 签名 appcast。一次性前置见 `docs/发布指南.md`。 -- 不上 App Store 的原因:沙盒禁 SMC(温度/风扇)、清理功能需授权目录改造;如日后做 MAS 精简版,是独立目标。 - -## 架构约定 - -- 所有共享类型在 `Sources/MacPulse/Models.swift`,不要在模块文件里重复定义。 -- 采样调度:`SystemMonitor`(2s 快 tick / 6s 慢 tick)与 `UsageStore`(60s)都是 @MainActor ObservableObject,实际采样在各自串行 GCD 队列上做,读取器(Reader/Scanner)的跨 tick 状态只允许在对应队列上访问。 -- SMC:`flt ` 类型是小端 float32,ui16/ui32 是大端——别改反。M5 温度键前缀 Tp/Te/Tf(CPU)、Tg(GPU),风扇 F{i}Ac。 -- AI 计价:PricingTable 是 2026-07-06 快照;Sonnet 5 介绍价 2026-08-31 到期后要把 2.00/10.00 改成 3.00/15.00(cacheW 3.75 / cacheR 0.30)。 -- 去重语义对齐 ccusage v18:文件按最早时间戳升序,全局 Set 按 `messageId:requestId`,任一缺失不去重。 -- 清理功能(删文件,安全第一):`CleanupScanner.isSafeToDelete` 三重守卫是防线,改动务必重跑沙盒测试(见下)。白名单只含可再生缓存,`protectedPaths` 绝不能放 home 本身(会用 hasPrefix 把 home 下全拒)。路径归一化必须纯词法(不能用 `NSString.standardizingPath`,它解析符号链接、对存在与否行为不一致)。枚举顶层项用 FileManager(不能用 `du -d 1`,只列子目录漏文件)。 -- 内存回收(MemoryReleaser)用 mmap 申请+触碰+munmap,上限 min(3GB, 空闲一半);purge 需 root 不用。 - -## 清理安全测试(改 CleanupScanner 后必跑) - -`/private/tmp/.../scratchpad/safety_test.swift`(23 条守卫用例)+ `e2e_test.swift`(假 home 端到端)。 -核心不变量:危险路径(文档/偏好/pnpm store/SSH/iCloud/路径穿越/系统文件)必须全部拒删,合法缓存项可删,符号链接只删链接不碰目标。 - -## 验证 - -改动后:`./scripts/build.sh && open dist/MacPulse.app`,确认菜单栏出现 `C.. M.. $..` 标签; -AI 费用可用独立脚本重算对比(解析 JSONL 今日事件 × 价格表,误差应在分钟级自然增量内)。 diff --git a/CHANGELOG.md b/CHANGELOG.md index a214797..cdde5b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,13 @@ 本项目采用语义化版本号;构建号单独递增,用于 Sparkle 比较更新。 -## [0.10.0] - 2026-07-17 +## [Unreleased] ### Added - 可选 Google 登录;登录成功即以打码昵称加入 Token 与 API 等价费用周榜。 - 游客无需登录即可浏览公开榜单,且所有本地监控功能保持可用。 - 登录用户可查看个人名次、主动公开完整昵称、立即同步或退出并删除榜单数据。 -- 轻量运营后台:排行榜成员、日活、次日/7 日/30 日留存、版本分布和异常用户隐藏。 - 官网公开榜单与独立隐私说明页。 ### Privacy and security diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 1a0a1c8..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,34 +0,0 @@ -# MacPulse(Mac监控器) - -Swift 菜单栏系统监控 app:系统指标(CPU/内存/网络/磁盘/温度/风扇)+ AI token 用量与费用预估(解析 ~/.claude/projects 与 ~/.codex/sessions 的会话 JSONL)。 - -## 构建 - -- 只用 `./scripts/build.sh`(编译 + 打包 dist/MacPulse.app + ad-hoc 签名),不要直接裸跑 `swift build`。 -- 本机 CLT 损坏(两个旧版残留文件),build.sh 内置无 sudo workaround(`.clt-fix/`);永久修复方案见 README。2026-07 起本机已装 Xcode 26.6(xcode-select 指向 Xcode,SDK MacOSX26),workaround 段在 CLT 残留文件存在时仍会激活但无害。 -- 目标 macOS 14+,Swift 5 语言模式(tools-version 5.10)。 - -## 发布(官网分发,不上 MAS) - -- `./scripts/release.sh <版本> <递增构建号>`:构建 → Sparkle 嵌套签名 → Developer ID 签名(hardened runtime)→ notarytool 公证 → staple → DMG → 公证 DMG → 签名 appcast。一次性前置见 `docs/发布指南.md`。 -- 不上 App Store 的原因:沙盒禁 SMC(温度/风扇)、清理功能需授权目录改造;如日后做 MAS 精简版,是独立目标。 - -## 架构约定 - -- 所有共享类型在 `Sources/MacPulse/Models.swift`,不要在模块文件里重复定义。 -- 采样调度:`SystemMonitor`(2s 快 tick / 6s 慢 tick)与 `UsageStore`(60s)都是 @MainActor ObservableObject,实际采样在各自串行 GCD 队列上做,读取器(Reader/Scanner)的跨 tick 状态只允许在对应队列上访问。 -- SMC:`flt ` 类型是小端 float32,ui16/ui32 是大端——别改反。M5 温度键前缀 Tp/Te/Tf(CPU)、Tg(GPU),风扇 F{i}Ac。 -- AI 计价:PricingTable 是 2026-07-06 快照;Sonnet 5 介绍价 2026-08-31 到期后要把 2.00/10.00 改成 3.00/15.00(cacheW 3.75 / cacheR 0.30)。 -- 去重语义对齐 ccusage v18:文件按最早时间戳升序,全局 Set 按 `messageId:requestId`,任一缺失不去重。 -- 清理功能(删文件,安全第一):`CleanupScanner.isSafeToDelete` 三重守卫是防线,改动务必重跑沙盒测试(见下)。白名单只含可再生缓存,`protectedPaths` 绝不能放 home 本身(会用 hasPrefix 把 home 下全拒)。路径归一化必须纯词法(不能用 `NSString.standardizingPath`,它解析符号链接、对存在与否行为不一致)。枚举顶层项用 FileManager(不能用 `du -d 1`,只列子目录漏文件)。 -- 内存回收(MemoryReleaser)用 mmap 申请+触碰+munmap,上限 min(3GB, 空闲一半);purge 需 root 不用。 - -## 清理安全测试(改 CleanupScanner 后必跑) - -`/private/tmp/.../scratchpad/safety_test.swift`(23 条守卫用例)+ `e2e_test.swift`(假 home 端到端)。 -核心不变量:危险路径(文档/偏好/pnpm store/SSH/iCloud/路径穿越/系统文件)必须全部拒删,合法缓存项可删,符号链接只删链接不碰目标。 - -## 验证 - -改动后:`./scripts/build.sh && open dist/MacPulse.app`,确认菜单栏出现 `C.. M.. $..` 标签; -AI 费用可用独立脚本重算对比(解析 JSONL 今日事件 × 价格表,误差应在分钟级自然增量内)。 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index da01dfd..3f14c63 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,6 +15,10 @@ - 修改 `CleanupScanner` 必须覆盖危险路径、路径穿越与符号链接安全测试。 - 不记录 OAuth token、会话正文或真实项目路径。 +## 公开仓库边界 + +只提交用户或贡献者实际需要的文档。内部产品规划、未发布路线图、账号与部署标识、维护者发布手册和协作纪要应保存在仓库之外,或放入已忽略的 `docs/private/`;任何凭证与私钥都不得进入 Git 历史。 + ## Pull Request 请保持 PR 单一目的,并说明用户可见变化、验证方式和兼容性影响。涉及 UI 时附截图;涉及清理、钥匙串、签名或更新时,明确列出安全边界。 diff --git a/README.md b/README.md index b103613..62a7efa 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ open dist/MacPulse.app The package uses Swift 5 language mode, targets macOS 14+, and is built with Swift Package Manager. The build script compiles, assembles `dist/MacPulse.app`, generates the icon when needed, and applies an ad-hoc signature for local testing. -For release signing, notarization, Sparkle appcast generation, and Gatekeeper checks, follow [`docs/发布指南.md`](docs/发布指南.md). Do not distribute artifacts produced with `SKIP_NOTARIZE=1`. +Public release artifacts must be Developer ID-signed, notarized by Apple, and delivered through a signed Sparkle appcast. Maintainer credentials and operational runbooks are intentionally kept outside this public repository. Do not distribute artifacts produced with `SKIP_NOTARIZE=1`. ## Architecture highlights diff --git a/README.zh-CN.md b/README.zh-CN.md index 986e40d..14fc98a 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -130,7 +130,7 @@ open dist/MacPulse.app 项目采用 Swift 5 语言模式、目标 macOS 14+,使用 Swift Package Manager。构建脚本会编译、组装 `dist/MacPulse.app`、按需生成图标,并为本地测试执行 ad-hoc 签名。 -正式发布签名、公证、Sparkle appcast 和 Gatekeeper 检查见 [`docs/发布指南.md`](docs/发布指南.md)。`SKIP_NOTARIZE=1` 生成的产物不得公开分发。 +公开发布产物必须经过 Developer ID 签名、Apple 公证,并通过已签名的 Sparkle appcast 分发。维护者凭证与内部发布手册刻意保留在公开仓库之外;`SKIP_NOTARIZE=1` 生成的产物不得公开分发。 ## 架构要点 diff --git "a/docs/Gatekeeper\346\223\215\344\275\234\346\270\205\345\215\225.md" "b/docs/Gatekeeper\346\223\215\344\275\234\346\270\205\345\215\225.md" deleted file mode 100644 index 4ccb935..0000000 --- "a/docs/Gatekeeper\346\223\215\344\275\234\346\270\205\345\215\225.md" +++ /dev/null @@ -1,82 +0,0 @@ -# MacPulse 正式发布:需要你操作的 4 件事 - -这份清单只包含必须由账户持有者确认、输入凭据或保管私钥的步骤。 -不要把 Apple ID 密码、App 专用密码、Team ID 凭据、`.p12` 或 Sparkle 私钥发到聊天中。 - -## 1. 创建空的 GitHub 公开仓库 - -GitHub 已确认当前连接账号为 `hepinga`。请创建: - -- Owner:`hepinga` -- Repository name:`MacPulse` -- Visibility:`Public` -- **不要**勾选 README、`.gitignore` 或 License,保持空仓库 - -完成后只需回复:`GitHub 空仓库已创建`。 - -另外,本机 GitHub CLI 已安装。如果 Codex 已发起设备登录,请在 - 输入终端显示的一次性代码并批准 `hepinga`;不要把 GitHub token 发到聊天中。 - -## 2. 创建 Developer ID Application 证书 - -1. 打开 Xcode → Settings → Accounts。 -2. 选中 Apple Developer Program 账号。 -3. Manage Certificates… → `+` → Developer ID Application。 -4. 等待证书出现在列表中。 - -完成后在你自己的终端执行: - -```sh -security find-identity -v -p codesigning | grep "Developer ID Application" -``` - -只要回复:`Developer ID 已创建`,不要粘贴证书私钥。 - -## 3. 存储 Apple 公证凭据 - -先在 Apple Account 生成 App 专用密码,再在你自己的终端执行: - -```sh -cd '' -./scripts/setup-notary.sh -``` - -脚本会交互读取 Apple ID、Team ID 和 App 专用密码,并存到本机钥匙串的 -`macpulse-notary` profile。请在本机直接输入,不要通过聊天传递。 - -完成后只需回复:`macpulse-notary 已配置`。 - -## 4. 备份两把发布私钥 - -### Developer ID - -在“钥匙串访问”中展开 Developer ID Application 证书,连同私钥导出为强密码保护的 `.p12`, -存入加密密码库或离线介质。 - -### Sparkle EdDSA - -本机已生成 Sparkle 私钥。在安全的临时目录导出: - -```sh -mkdir -m 700 /private/tmp/macpulse-key-backup -cd '' -.build/artifacts/sparkle/Sparkle/bin/generate_keys -x /private/tmp/macpulse-key-backup/sparkle-ed25519-private-key.txt -``` - -立即把文件放入加密密码库/加密离线介质,确认可恢复后,用 Finder 把临时文件移入废纸篓并清空。 -不要粘贴或截图私钥内容。 - -全部完成后回复:`Developer ID 和 Sparkle 私钥已备份`。 - -## 完成后 - -你只要回复下面四项的完成状态,不需要发任何密码或 token: - -```text -GitHub 空仓库已创建 -Developer ID 已创建 -macpulse-notary 已配置 -Developer ID 和 Sparkle 私钥已备份 -``` - -之后的仓库推送、标签、签名、公证、GitHub Release、下载站/appcast 更新以及更新链验证都由 Codex 继续完成。 diff --git "a/docs/GitHub\350\243\205\344\277\256\350\260\203\347\240\224\344\270\216\346\226\271\346\241\210.md" "b/docs/GitHub\350\243\205\344\277\256\350\260\203\347\240\224\344\270\216\346\226\271\346\241\210.md" deleted file mode 100644 index 8d48413..0000000 --- "a/docs/GitHub\350\243\205\344\277\256\350\260\203\347\240\224\344\270\216\346\226\271\346\241\210.md" +++ /dev/null @@ -1,182 +0,0 @@ -# MacPulse GitHub 装修调研与方案 - -> 调研日期:2026-07-18 -> 目标:让第一次进入仓库的人在 30 秒内看懂“它是什么、为什么值得下载、是否可信、如何参与”,同时保持版本、隐私和分发信息真实。 - -## 一、结论先行 - -优秀项目的共同点不是“徽章越多越好”,而是把仓库首页当作产品落地页:首屏讲清定位与下一步,真实图片证明产品存在,结构化信息降低理解成本,社区文件让反馈可执行。MacPulse 应采用以下组合: - -1. 英文 `README.md` 作为默认首页,`README.zh-CN.md` 提供完整中文镜像,首屏双向切换。 -2. 只保留能回答事实问题的徽章:Release、CI、许可证、系统要求、芯片架构、技术栈、Beta 状态、本地优先。 -3. 用真实构建截图组成 Hero 与图集;截图默认开启隐私模式,不展示凭证、路径、后台或失败状态。 -4. 把下载、官网、隐私说明放在首屏,把维护细节折叠或链接到开发文档。 -5. 用 Issue 表单、PR 模板、Topics 与标签建立可搜索、可分流的社区入口。 -6. 明确区分 **v0.9.0 正式 Release** 与 `main` 上的 **v0.10 未发布预览**,不制造已经发布的错觉。 - -## 二、优秀案例与可复用模式 - -| 项目 | 首页做法 | 可复用模式 | MacPulse 的取舍 | -| --- | --- | --- | --- | -| [LocalSend](https://github.com/localsend/localsend) | 多语言入口、少量事实徽章、下载入口、跨平台截图 | 语言切换出现在首屏;“立即获取”比安装细节更靠前;截图承担产品解释 | 学习双语入口和下载层级,不照搬跨平台叙事 | -| [Ice](https://github.com/jordanbaird/Ice) | 图标、品牌横幅、系统要求与版本徽章、截图画廊 | 原生 macOS 项目适合以图标和宽屏视觉建立第一印象 | 学习原生感和画廊;MacPulse 不增加无事实依据的平台徽章 | -| [MonitorControl](https://github.com/MonitorControl/MonitorControl) | 清晰下载 CTA、状态徽章、主截图、多图网格 | 先证明“可以下载并运行”,再解释功能;多图覆盖关键任务 | 学习 CTA 与多图布局;不复制与显示器控制相关的技术信息 | -| [Stats](https://github.com/exelban/stats) | 大图优先、直接 Release 入口、语言列表 | 菜单栏工具需要尽快展示信息密度和原生界面 | 学习图片优先和直接下载;MacPulse 只维护两份高质量语言文档 | - -这些案例的共同结构可以归纳为: - -```text -品牌与一句话定位 - ├─ 语言 / 版本 / 平台事实 - ├─ 下载 / 官网 / 隐私主入口 - ├─ 一张宽屏产品证据图 - ├─ 核心价值与关键功能 - ├─ 多图画廊 - └─ 要求 / 隐私 / 开发 / 贡献 -``` - -## 三、GitHub 官方规范 - -### README 与相对链接 - -GitHub 会自动呈现仓库根目录等位置的 README,并建议 README 说明项目用途、入门方式、帮助入口和维护者信息。文档内图片、文件与目录宜使用相对路径,保证分支和克隆环境中的链接仍然成立。 - -- [About READMEs — GitHub Docs](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes) -- [Basic writing and formatting syntax / Relative links — GitHub Docs](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/basic-writing-and-formatting-syntax#relative-links) - -### Topics - -Topics 用于发现和分类仓库。名称只能包含小写字母、数字和连字符;每个仓库最多 20 个。应优先覆盖平台、技术栈、产品形态、核心能力与集成对象,不把营销口号拆成 Topics。 - -- [Classifying your repository with topics — GitHub Docs](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics) - -### Social Preview - -GitHub 建议自定义社交预览图采用 2:1 画幅,推荐至少 1280×640,文件小于 1 MB。预览图在分享链接时承担“品牌识别 + 一句话解释”,不应塞入小字号功能清单。 - -- [Customizing your repository's social media preview — GitHub Docs](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/customizing-your-repositorys-social-media-preview) - -### 社区健康文件与安全 - -Issue 表单通过结构化字段提高复现质量;PR 模板用于统一验证、隐私与变更说明。公开安全问题不应要求用户粘贴凭证,仓库应引导使用私密漏洞报告或安全策略中的私密渠道。 - -- [Configuring issue templates for your repository — GitHub Docs](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository) -- [Creating a pull request template for your repository — GitHub Docs](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository) -- [Adding a security policy to your repository — GitHub Docs](https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository) - -## 四、MacPulse 当前问题 - -装修前的首页信息丰富,但存在以下阻力: - -- 首屏缺少强定位、语言切换、下载与隐私入口,读者要滚动后才知道下一步。 -- 文字很长,产品价值、用户功能、实现细节和本机维护历史混在同一层级。 -- 缺少一组经过隐私处理的真实产品图,外部读者无法快速判断完成度与界面形态。 -- Release 事实与开发分支状态容易混淆:正式 Sparkle feed 仍是 v0.9.0,而 `main` 已包含 v0.10 预览内容。 -- Issue 分类较少,缺 PR 模板、Issue 配置与统一标签色板。 -- 仓库 About、Topics 与 Social Preview 尚未形成完整的发现入口。 - -## 五、推荐信息架构 - -### 首屏 - -1. 图标、项目名和一句话定位。 -2. `English · 简体中文` 双向切换。 -3. 两行事实徽章。 -4. 下载、官网、图集与隐私四个入口。 -5. 一张 16:9 宽屏 Hero。 -6. 紧随其后的版本事实提示:v0.9.0 已发布、v0.10 为未发布预览、App UI 仍以中文为主。 - -### 正文 - -- **核心价值**:系统脉搏、AI 用量、额度感知、本地优先工具。 -- **图集**:主题差异、分析模式、公开官网;后续有稳定自动化后再补刘海与 Skills 独立截图。 -- **功能矩阵**:系统、AI 用量、额度、体验与可选工具。 -- **下载要求**:Apple Silicon、macOS 14+、签名与公证。 -- **隐私边界**:本地数据、允许联网的可见功能、不采集的内容。 -- **开发与贡献**:构建脚本、发布文档、Issue/PR 入口。 - -维护者专属内容(例如特定机器上的 CLT 历史残留、签名凭证配置、公证排障)不应占据用户首页主叙事,应放在开发或发布文档中。 - -## 六、徽章准则 - -### 保留 - -| 徽章 | 回答的问题 | -| --- | --- | -| Latest Release | 当前可下载版本是什么 | -| CI | 主线是否通过自动检查 | -| MIT | 使用与分发的许可是什么 | -| macOS 14+ | 最低系统要求是什么 | -| Apple Silicon | 支持什么硬件架构 | -| Swift / SwiftUI | 主要技术栈是什么 | -| Public Beta | 产品成熟度是什么 | -| Local-first | 隐私和数据处理的核心承诺是什么 | - -### 不使用 - -- 访问量、Star 数、Fork 数等会制造热度但不提高理解的徽章。 -- 没有自动验证来源的“100% privacy”“production ready”等宣称。 -- Homebrew 徽章或 `brew install macpulse`:当前同名 cask 指向另一个产品,容易误装。 -- 把 `main` 中的版本号做成已发布版本徽章;Release 徽章必须动态读取 GitHub Releases。 - -## 七、图片准则与本次资产 - -### 准则 - -- 产品截图必须来自真实构建,优先成功状态;不得用设计稿伪装成运行结果。 -- 开启隐私模式,隐藏真实项目名、用户名、路径、Token、凭证和管理后台。 -- 排除“服务不可用”、登录错误、空白骨架等不适合作为产品证据的画面。 -- README 图采用仓库相对路径并提供有意义的 `alt` 文本。 -- 三列图在窄屏会缩小,单图分析界面保留独立宽屏展示。 -- Social Preview 固定为 1280×640、纯色背景、小于 1 MB;Hero 保留 1600×900 宽屏版本。 - -### 本次资产清单 - -| 文件 | 用途 | 尺寸 | -| --- | --- | --- | -| `docs/assets/github/hero.webp` | README 首屏 Hero | 1600×900 | -| `docs/assets/github/dashboard-hud.png` | HUD 主题 | 923×768 | -| `docs/assets/github/dashboard-led.png` | LED 主题 | 923×768 | -| `docs/assets/github/dashboard-classic.png` | 经典主题 | 923×768 | -| `docs/assets/github/analysis-mode.png` | AI Token 分析模式 | 923×768 | -| `docs/assets/github/website-home.png` | 公开官网 | 1265×712 | -| `docs/assets/github/social-preview.jpg` | GitHub Social Preview | 1280×640 | - -本轮没有为了凑数量伪造刘海或 Skills 独立截图:macOS 辅助功能未稳定暴露这些瞬时界面,且全屏捕获可能带入工作区隐私。后续应在干净桌面与演示数据环境中补拍,再替换图集,而不是拼接虚假状态。 - -## 八、Topics、标签与社区分类 - -### Topics - -建议 15 个(低于 GitHub 的 20 个上限): - -`macos`、`swift`、`swiftui`、`menu-bar`、`menubar-app`、`macos-app`、`system-monitor`、`apple-silicon`、`cpu-monitor`、`memory-monitor`、`smc`、`ai-usage`、`token-usage`、`claude-code`、`codex-cli` - -### 标签 - -| 类别 | 标签 | 色彩策略 | -| --- | --- | --- | -| 类型 | `bug`、`enhancement`、`documentation` | 红、青、蓝 | -| 风险 | `privacy`、`security` | 紫、深红 | -| 区域 | `area: system`、`area: ai-usage`、`area: quota`、`area: cleanup`、`area: skills`、`area: ui`、`area: website` | 统一浅蓝 | -| 社区状态 | `needs triage`、`good first issue`、`help wanted` | 灰、紫、绿 | - -原计划写“六个 `area:*`”但同时列出了七个真实产品区域。本方案按产品结构保留七个,避免把官网或 UI 问题塞进不相关分类。仓库中的 `.github/labels.yml` 作为名称、说明与颜色的可审查来源;线上标签需通过 GitHub 设置同步。 - -## 九、上线检查 - -- [ ] `README.md` 与 `README.zh-CN.md` 首屏互链,主张一致。 -- [ ] Release 徽章动态读取,正文明确 v0.9.0 / v0.10 边界。 -- [ ] 所有相对链接和图片路径在分支上存在。 -- [ ] Social Preview 为 1280×640 且小于 1 MB。 -- [ ] README 在 GitHub PR 页面上检查桌面和窄屏布局。 -- [ ] CI 通过,且本任务没有修改 Swift 产品逻辑或发布新版本。 -- [ ] 仓库 About 使用准确简介与官网链接。 -- [ ] Topics、标签和 Social Preview 已在线同步;无法登录时明确标记为阻塞项。 -- [ ] PR 保持未合并,由维护者最后确认。 - -## 十、仓库元数据建议值 - -- **Description**:`Native macOS menu bar monitor for system health, Claude Code & Codex usage, cost estimates, quotas, and local-first tools.` -- **Website**:`https://macpulse-monitor.peaceaii.chatgpt.site` -- **Social Preview**:`docs/assets/github/social-preview.jpg` diff --git a/docs/PRD.html b/docs/PRD.html deleted file mode 100644 index 5d91fcc..0000000 --- a/docs/PRD.html +++ /dev/null @@ -1,333 +0,0 @@ -Token 监控台 · PRD - - -
-
-
MacPulse · 产品需求文档 (PRD)
-

Token 监控台

-

在 MacPulse 菜单栏应用里,把「AI 用量」升级成一个能按多维度筛选、实时看消耗与花费、并给出省钱信号的 Token 监控台。

-
- 版本 v1 draft - 日期 2026-07-06 - 依据 调研报告 - 载体 MacPulse(SwiftUI 菜单栏 app) -
-
- - - - -

1 目标与非目标

-
-
看得清

任意时间窗内消耗多少 token、折算多少钱,一眼可见。

-
分得开

能按时间 / 工具 / 项目 / 模型 / token 类型自由切换钻取。

-
省得下

缓存命中率、最贵会话、模型占比给出可执行的省钱信号。

-
跟得住

burn rate + 预算/额度预测,知道"还能用多久、几点撞额度"。

-
-

非目标(本期不做):不做云端同步 / 多机聚合;不做团队 per-user 账单;不宣称与厂商官方账单分毫一致(订阅口径为名义美元);不采集需要企业管理员权限的 Copilot 数据;思考 token 与回答 token 的分离(JSONL 通常并入 output,不可靠)。

- - -

2 用户与核心场景

-

主用户 = 重度使用 AI 编程工具的个人开发者(你自己),关心花销、想优化、订阅额度紧张。

-
    -
  • 日常一瞥 — 菜单栏常驻"今日花了多少",点开看今日/本周趋势。
  • -
  • 月底复盘 — 切到 30 天,看哪个项目、哪个模型最烧钱,对比上月。
  • -
  • 省钱优化 — 看缓存命中率是否偏低、有没有该降档却在用贵模型的活、揪出最贵的几次会话。
  • -
  • 额度预警 — 订阅用户看当前 5 小时块还剩多少、按当前速度几点用完。
  • -
  • 跨工具对比 — 同时用 Claude Code 和 Codex/Cursor,想知道各占多少。
  • -
- - -

3 数据源与工具支持

-

全部本地读取,零网络、零登录。成本按「token × 分模型分类型单价」离线计算(复用已有 PricingTable)。

-
- - - - - - - - - - -
工具期次数据源能拿到说明
Claude Code已上线~/.claude/projects/**/*.jsonl四类 token · 成本 · 模型 · 项目 · 会话已实现,复用现有 UsageScanner
Codex CLI一期~/.codex/sessions/**/*.jsonlinput/cached/output/reasoning · 模型 · cwd · git取每会话末条 total_token_usage,勿逐行求和
Cursor二期state.vscdb (SQLite)input/output token · 模型 · 会话(无官方成本)只读快照/复制后读;标注"本地估算"
Roo Code二期task history 文件四类 token + totalCost + workspace字段最全;有历史才有数据
Gemini CLI不支持默认不落盘标注"需开 OTEL 遥测"
GitHub Copilot不支持本地无 per-request token标注"仅企业 Metrics API"
-
-
统一数据模型:所有采集器归一化到同一 UsageEvent(工具来源 · 时间 · 模型 · 四类 token · 项目 · 会话 · 可选成本)。UI 与聚合层只认这个模型,新增工具 = 新增一个采集器,不动上层。
- - -

4 筛选维度

-

顶部一排筛选器,任意组合;P0 一期,P1 二期,P2 视情况。

-
- - - - - - - - - - - - - -
维度取值优先级可行性
时间24 小时 / 今日 / 7 天 / 30 天 / 自定义区间P0
工具Claude Code / Codex(/ Cursor / Roo)/ 全部P0高(见 §3)
项目按项目目录(cwd)聚合P0
模型按具体模型(Opus/Sonnet/Fable/GPT-5…)P0
Token 类型输入 / 输出 / 缓存写 / 缓存读P0
会话 / 5h 块按 sessionId / 5 小时滚动窗口P0
时段小时 × 星期(热力图钻取)P1
git 分支 / 子目录比项目更细P2中(部分缺失降级)
工具调用Bash/Read/Edit/MCP…P2中(需归因)
-
- - -

5 展示指标

-
    -
  • 总成本(选定窗口,按单位设置显示 ¥/$)+ 环比 delta(较上一同长度周期 ↑↓%)
  • -
  • 总 token,并拆 输入 / 输出 / 缓存写 / 缓存读 四类
  • -
  • 缓存命中率 %缓存已省金额(cache_read 相对全价省下的钱)
  • -
  • Burn rate($/小时 或 token/分钟)+ 预测(本月预估总额 / 本 5h 块预计耗尽时间)
  • -
  • 额度使用率 %(5 小时块 或 用户设的月度预算,进度环)
  • -
  • 每会话平均成本 / 最贵会话 Top N
  • -
  • 上下文体量:每请求平均 / P95 输入侧 token
  • -
- - -

6 功能需求

-
    -
  • FR-1
    筛选器栏 — 顶部时间段分段控件(24h/今日/7天/30天)+ 工具/项目/模型下拉多选;筛选状态驱动下方所有视图联动刷新。
  • -
  • FR-2
    概览卡 — 大字总成本 + 环比;总 token 四类拆分;缓存命中率;调用次数。数值变化走弹簧动画。
  • -
  • FR-3
    趋势图 — 按选定窗口的成本/ token 时间序列(折线或堆叠面积),可切换"按模型堆叠 / 按 token 类型堆叠"。
  • -
  • FR-4
    模型拆分 — 甜甜圈或堆叠条展示各模型 token/成本占比 + 明细表(可排序)。
  • -
  • FR-5
    项目/工具拆分 — 按项目、按工具的成本排名条形表,点击可下钻为该项目的趋势。
  • -
  • FR-6
    缓存分析 — 命中率趋势(带目标参考线)+ 已省金额 + "缓存浪费"提示(写了却没命中)。
  • -
  • FR-7
    Burn rate 与额度 — 当前 5h 块进度环 + 燃烧率 + 耗尽 ETA;可选月度预算,超阈值变色告警。
  • -
  • FR-8
    Top N 最贵会话 — 表格,列出最贵会话(项目 · 模型 · token · 成本 · 时间),定位可优化点。
  • -
  • FR-9
    时段热力图 — 小时 × 星期,颜色深浅=消耗量。P1
  • -
  • FR-10
    菜单栏摘要 — 常驻显示今日成本(按单位设置);点击直达监控台。
  • -
  • FR-11
    显示设置 — 计量单位与货币切换(见 §7)。
  • -
- - -

7 显示设置 · 用户追加需求

-

监控台右上角齿轮 → 设置面板,用 @AppStorage 持久化,全局生效。

-
- - - - - - - -
设置项选项默认作用范围
Token 计量单位中文单位(万 / 百万 / 千万 / 亿)· 国际单位(K / M / B)· 自动中文单位所有 token 数字:菜单栏、卡片、图表轴、明细
货币¥ 人民币 · $ 美金¥ 人民币所有金额显示
汇率(USD→CNY)可编辑数字,默认 ≈ 7.2,可选联网自动获取7.2 / 自动人民币折算
-
-
中文单位示例:12,345,678 token → 选中文单位显示「1234.6 万」;123,456,789 → 「1.23 亿」。货币示例:$8.50 → 选人民币显示「¥61.2」(按 7.2 汇率)。落地:扩展 ByteFormat.tokens() 支持中文模式,抽象一个读全局设置的货币格式化函数替换写死的 $
- - -

8 UI / UX 规格 · 用户追加需求

-

整体符合 macOS 最新设计规范(Tahoe / Liquid Glass 语言),含微交互与微动效。

-
工具链约束(已与你确认):本机只有 CLT(SDK 15.2),无完整 Xcode,真正的 Liquid Glass API(.glassEffect(),macOS 26 SDK)编译不了。已定方案:用当前工具链(SDK 15 SwiftUI)逼近最新设计,视觉接近约 8 成;如需 100% 保真,后续装 Xcode 26+ 再升级。
-

视觉

-
    -
  • 玻璃材质 — 区块用 .regularMaterial / .ultraThinMaterial 半透明背景 + 模糊,营造层次与通透感。
  • -
  • 卡片化 — 大圆角、细边框、柔和阴影;概览指标做成玻璃卡。
  • -
  • 系统字体与配色 — SF 字体、语义色(good/warn/critical)与强调色分离;明暗双主题。
  • -
  • 信息密度 — 概览在前、明细在后;状态用色块/进度环编码,一眼看出需关注项。
  • -
-

微交互 / 微动效

-
    -
  • 数值变化走 .spring 弹簧动画(成本、token 平滑滚动到新值)。
  • -
  • tab / 时间段切换用 matchedGeometryEffect 转场;图表入场淡入+生长。
  • -
  • hover 高亮、按压缩放反馈;筛选器切换即时联动。
  • -
  • 扫描/加载用流畅进度而非突兀空屏;菜单栏数值平滑过渡。
  • -
  • 尊重「减弱动态效果」(reduce-motion)。
  • -
-

信息架构

-

「清理」已并入系统 tab(系统管理的一部分)。「AI 用量」tab 升级为 Token 监控台:顶部筛选器 → 概览卡 → 趋势 → 拆分(模型/项目/工具)→ 缓存 → burn rate/额度 → Top N,右上角齿轮进设置。

- - - - -

9 技术方案

-
    -
  • 采集层 — 每工具一个 UsageSource(scanAll → [UsageEvent]):ClaudeCodeSource(已有)、CodexSource(新)、后续 CursorSource/RooSource。增量缓存(size+mtime)、跨文件去重沿用现有模式。
  • -
  • 模型层 — 统一 UsageEvent;聚合器 UsageAggregator 接收筛选条件(时间/工具/项目/模型)输出各视图数据结构(纯函数,可测)。
  • -
  • 计价 — 复用 PricingTable(已含 Claude/GPT/Gemini + 缓存 1h/5m 分档 + 200K 分层);Codex 的 gpt-5.x-codex 补进价目表。
  • -
  • 去重 — Claude 用 messageId:requestId;Codex 取会话末条 total_token_usage;各源各自防重后再合并。
  • -
  • 格式化NumberFormatting 统一:token 单位(中文/国际)+ 货币(¥/$ + 汇率),读 @AppStorage
  • -
  • 刷新 — 沿用 UsageStore 的 60s 后台扫描 + 在途保护;筛选器变更即时本地重聚合(不重扫)。
  • -
  • 性能 — 冷启动全量解析后常驻内存事件表(90 天窗口);筛选/切维度为内存内计算,秒开。
  • -
- - -

10 分期计划

-

一期 · 监控台骨架 + 核心维度

Codex 采集器接入;统一 UsageEvent + 聚合器;筛选器(时间/工具/项目/模型/token 类型/会话·5h 块);概览卡 + 趋势 + 模型拆分 + 缓存分析 + burn rate/额度 + Top N;显示设置(单位/货币/汇率);macOS 玻璃视觉 + 微动效第一轮。

-

二期 · 更多数据源 + 高级维度

Cursor 采集器(SQLite,标注估算)+ Roo 采集器;时段热力图;git 分支/子目录维度;月度预算与告警;导出(CSV/JSON)。

-

三期 · 效率与深度

每千行代码成本 / 每会话成本;工具调用维度归因;计费模式切换(订阅额度 vs API);自定义标签维度。

- - -

11 验收标准

-
    -
  • 切换 24h/今日/7天/30天,所有视图正确联动,秒级响应。
  • -
  • Claude Code + Codex 的总成本与独立脚本(ccusage 口径)交叉验证误差在自然增量内。
  • -
  • 模型 / token 类型 / 项目拆分之和 = 总量(无漏算重算)。
  • -
  • 缓存命中率、burn rate、5h 块耗尽预测口径与 ccusage/官方 /cost 一致。
  • -
  • Token 单位与货币切换全局即时生效,中文单位/人民币显示正确(含汇率)。
  • -
  • 玻璃材质 + 微动效在明暗主题下均正常;尊重 reduce-motion。
  • -
  • 稳态资源占用不显著高于现状(菜单栏 app 该轻量)。
  • -
- - -
diff --git a/docs/PRD.md b/docs/PRD.md deleted file mode 100644 index 738b9a9..0000000 --- a/docs/PRD.md +++ /dev/null @@ -1,76 +0,0 @@ -# Token 监控台 — PRD(开发参照版) - -> 面向开发的精简版。完整可视化版见 docs/PRD.html。依据:docs/调研报告.html(2026-07-06)。 - -## 1. 目标 -在 MacPulse 把「AI 用量」tab 升级为 Token 监控台:多维度筛选、实时看消耗与花费、给省钱信号、burn rate/额度预测。 -非目标:云端同步/多机聚合、团队 per-user 账单、与厂商官方账单分毫一致、Copilot 企业数据、思考 token 分离。 - -## 2. 数据源与工具支持 -全部本地读取,离线计价(复用 PricingTable)。归一化到统一 `UsageEvent`。 - -| 工具 | 期次 | 数据源 | 说明 | -|---|---|---|---| -| Claude Code | 已上线 | `~/.claude/projects/**/*.jsonl` | 复用现有 UsageScanner | -| Codex CLI | 一期 | `~/.codex/sessions/**/*.jsonl` | 取每会话末条 `total_token_usage`,勿逐行求和;字段:input/cached_input/output/reasoning tokens、turn_context.model、session_meta.cwd/git、顶层 timestamp | -| Cursor | 二期 | `state.vscdb`(SQLite,cursorDiskKV 表 bubble 的 tokenCount) | 只读快照/复制后读;无官方成本→标注"本地估算";composerData.modelName 取模型 | -| Roo Code | 二期 | task history 文件 | 字段最全(含 totalCost+缓存+workspace);有历史才有数据 | -| Gemini CLI | 不支持 | — | 默认不落盘,需 OTEL 遥测 | -| GitHub Copilot | 不支持 | — | 本地无 per-request token,仅企业 Metrics API | - -**口径坑**:成本不在文件里,按 token×分模型分类型单价算;订阅用户美元是名义值,真实约束是 5h 块额度,两口径不混。 - -## 3. 筛选维度 -- P0(一期):时间(24h/今日/7天/30天/自定义)、工具、项目(cwd)、模型、token 类型(输入/输出/缓存写/缓存读)、会话·5h 块 -- P1(二期):时段(小时×星期热力图) -- P2(三期):git 分支/子目录、工具调用(Bash/Read/Edit/MCP) - -## 4. 展示指标 -总成本(¥/$,含环比 delta)、总 token 四类拆分、缓存命中率 %+已省额、burn rate($/h 或 token/min)、预测(本月预估/5h 块耗尽 ETA)、额度使用率 %、每会话均成本+最贵会话 Top N、上下文体量(每请求均/P95 输入 token)。 - -## 5. 功能需求 -- FR-1 筛选器栏(时间分段 + 工具/项目/模型多选,联动) -- FR-2 概览卡(大字成本+环比;token 四类;缓存命中;调用数;弹簧动画) -- FR-3 趋势图(折线/堆叠面积,可切"按模型/按 token 类型"堆叠) -- FR-4 模型拆分(甜甜圈/堆叠条 + 可排序明细表) -- FR-5 项目/工具拆分(条形排名,点击下钻) -- FR-6 缓存分析(命中率趋势+目标线、已省额、缓存浪费提示) -- FR-7 burn rate 与额度(5h 块进度环 + 燃烧率 + 耗尽 ETA;可选月度预算超阈告警) -- FR-8 Top N 最贵会话表 -- FR-9 时段热力图(P1) -- FR-10 菜单栏摘要(今日成本,点击直达) -- FR-11 显示设置(见 §6) - -## 6. 显示设置(用户追加需求,@AppStorage 全局持久化) -| 设置项 | 选项 | 默认 | -|---|---|---| -| Token 计量单位 | 中文单位(万/百万/千万/亿)· 国际(K/M/B)· 自动 | 中文单位 | -| 货币 | ¥ 人民币 · $ 美金 | ¥ 人民币 | -| 汇率 USD→CNY | 可编辑(默认≈7.2)· 可选联网自动 | 7.2/自动 | - -示例:12,345,678 token → 中文单位「1234.6 万」;123,456,789 → 「1.23 亿」。$8.50 → ¥61.2(7.2 汇率)。 -落地:扩展 `ByteFormat.tokens()` 支持中文模式;抽象读全局设置的货币格式化函数替换写死的 `$`。 - -## 7. UI/UX(用户追加需求) -符合 macOS 最新设计(Tahoe/Liquid Glass),含微交互/微动效。 -**工具链约束(已确认):**本机仅 CLT(SDK 15.2),无 Xcode,真 Liquid Glass API(`.glassEffect()`,macOS 26 SDK)编译不了。**已定:用 SDK 15 SwiftUI 逼近**(视觉约 8 成);100% 保真需装 Xcode 26+。 -- 视觉:`.regularMaterial`/`.ultraThinMaterial` 玻璃背景+模糊、大圆角卡片、SF 字体、语义色与强调色分离、明暗双主题、概览在前明细在后。 -- 微动效:`.spring` 数值动画、`matchedGeometryEffect` 转场、图表入场淡入生长、hover 高亮、按压缩放、平滑加载;尊重 reduce-motion。 -- 信息架构:清理已并入「系统」tab;「AI 用量」升级为 Token 监控台(筛选器→概览→趋势→拆分→缓存→burn rate/额度→Top N,齿轮进设置)。 - -## 8. 技术方案 -- 采集层:每工具一个 `UsageSource`(scanAll→[UsageEvent]);ClaudeCodeSource(已有)、CodexSource(新)、CursorSource/RooSource(二期);增量缓存(size+mtime)+ 跨文件去重沿用现有模式。 -- 模型层:统一 `UsageEvent`(工具·时间·模型·四类 token·项目·会话·可选成本);`UsageAggregator` 纯函数按筛选条件出各视图数据。 -- 计价:复用 PricingTable(含缓存 1h/5m 分档 + 200K 分层);补 gpt-5.x-codex 价目。 -- 去重:Claude 用 messageId:requestId;Codex 取会话末条 total_token_usage;各源各自防重再合并。 -- 格式化:统一 NumberFormatting(token 单位 + 货币 + 汇率,读 @AppStorage)。 -- 刷新:沿用 UsageStore 60s 后台扫描 + 在途保护;筛选变更即时内存重聚合不重扫。 -- 性能:冷启动全量解析后常驻内存事件表(90 天窗口),切维度秒开。 - -## 9. 分期 -- 一期:Codex 采集 + 统一模型/聚合器 + 核心筛选维度 + 概览/趋势/模型拆分/缓存/burn rate/Top N + 显示设置 + 玻璃视觉与微动效第一轮 -- 二期:Cursor + Roo 采集 + 时段热力图 + git 分支维度 + 月度预算告警 + 导出 -- 三期:每千行/每会话成本 + 工具调用维度 + 计费模式切换 + 自定义标签 - -## 10. 验收 -时间段切换秒级联动;Claude+Codex 总成本与 ccusage 口径交叉验证;各维度拆分之和=总量;缓存/burn rate/5h 块口径对齐 ccusage 与官方 /cost;单位货币切换全局即时生效;玻璃+微动效明暗主题正常且尊重 reduce-motion;资源占用不显著升高。 diff --git "a/docs/ZOPC\350\264\246\345\217\267\347\244\276\345\214\272\344\270\216\346\234\215\345\212\241\345\271\263\345\217\260\350\256\276\350\256\241.md" "b/docs/ZOPC\350\264\246\345\217\267\347\244\276\345\214\272\344\270\216\346\234\215\345\212\241\345\271\263\345\217\260\350\256\276\350\256\241.md" deleted file mode 100644 index 50c9833..0000000 --- "a/docs/ZOPC\350\264\246\345\217\267\347\244\276\345\214\272\344\270\216\346\234\215\345\212\241\345\271\263\345\217\260\350\256\276\350\256\241.md" +++ /dev/null @@ -1,266 +0,0 @@ -# MacPulse × ZOPC 轻量账号与排行榜设计 - -更新日期:2026-07-17 -版本:轻量版 v2 -状态:0.10.0 最小闭环已实现,等待 Google OAuth 生产配置与线上验收 - -## 1. 本轮整体审查结论 - -上一版的问题是把登录、同步、公开、加入排行拆成多层状态,用户需要理解太多概念。首版应只保留两个状态: - -| 状态 | MacPulse 本地功能 | 公开榜单 | 我的排名 | 上传排行聚合 | -| --- | --- | --- | --- | --- | -| 游客 | 全部可用 | 可浏览 | 不可查看 | 不上传 | -| 排行榜成员 | 全部可用 | 可浏览 | 可查看 | 当日汇总幂等同步 | - -最终产品规则: - -> 不登录,MacPulse 所有现有功能照常使用;登录成功,就默认加入排行榜。 - -登录只为排行榜和未来 ZOPC 在线服务提供身份,不是 MacPulse 的使用门槛。 - -### 从上一版删除的复杂设计 - -- 删除“已登录但未加入排行榜”状态。 -- 删除“登录后再确认加入”的第二步。 -- 删除产品分析、同步数据、公开排行三个独立开关。 -- 删除首版的等级、实践值、社区积分和连续签到。 -- 删除第三种“随机匿名代号”选择。 -- 删除排行榜头像公开设置。 -- 删除首版月榜、总榜和个人复杂趋势。 -- 删除 App 内设备列表、授权中心和完整个人中心。 - -## 2. 产品结构 - - MacPulse 本地功能 - -> 排行榜入口 - -> 游客浏览公开周榜 - -> 登录后默认加入 - -> Token 消耗榜 - -> API 等价费用榜 - -> 打开 ZOPC 官网 - -> 社区与知识库 - -> 未来 ZOPC AI 服务 - -MacPulse 继续负责本地监控;ZOPC 官网负责社区、知识库和未来在线服务。App 不内嵌完整社区,也不把社区导航塞进主监控流程。 - -## 3. 最轻用户流程 - -### 3.1 游客 - -首次启动不出现登录提示。系统监控、Claude/Codex 本地统计、费用预估、清理、Skills、通知、主题、更新和官网入口全部正常工作。 - -排行榜入口只在 AI 监控台放一个轻量按钮: - - 社区排行 › - -游客点击后可以直接浏览本周公开排行榜。页面底部固定一条轻量区域: - - 登录后加入排行榜,并查看我的名次 - [ 使用 Google 登录并加入 ] - -### 3.2 登录即加入 - -排行榜卡片直接讲清同步边界,不再分成“登录”和“加入”两步: - - 加入排行榜 - - 登录后,MacPulse 每天同步一次: - Token 总量、API 等价费用、应用版本。 - 不会上传会话内容、项目、路径或第三方凭证。 - - [ 使用 Google 登录并加入 ] - -- 默认使用名称打码。 -- 登录后可主动打开“公开完整昵称”;未打开前只显示打码名。 -- 点击主按钮即表示登录并加入两个排行榜。 -- 登录成功后直接返回排行榜,并滚动到“我的排名”。 -- 登录取消或失败时留在公开榜单,不影响任何本地功能。 - -### 3.3 退出 - -App 内只提供一个操作:“退出排行榜”。 - -执行后立即停止同步、从公开榜单移除、清除本机登录凭证。ZOPC 网站账号本身保留;删除账号和云端数据在官网完成。 - -再次登录即再次加入,仍先看到相同的简短数据说明和名称预览。 - -## 4. 两个排行榜 - -首版只做本周榜,页面顶部只有一个切换: - - [ Token 消耗 ] [ API 等价费用 ] - -### 4.1 Token 消耗榜 - -口径与 MacPulse 现有监控台一致: - - input + output + cache write + cache read - -只展示整数 Token 总量,不展示用户使用的模型、项目、会话或各 Token 分项。 - -### 4.2 API 等价费用榜 - -使用 MacPulse 当前价格表计算的 USD API 等价费用。它不是 Claude、ChatGPT 或 Codex 订阅的真实扣款。 - -页面标题和“我的排名”旁始终显示“API 等价预估”。服务端使用整数 micro-USD 排名;用户界面可以换算人民币,但名次仍按 USD 基准值计算。 - -### 4.3 榜单行 - -首版每行只展示三项: - - 名次 | 名称 | Token 或费用 - -不展示头像、徽章、等级、积分、地区或设备信息。页面底部固定显示当前用户的名次,即使不在前 100 名也能看到自己。 - -## 5. 名称隐私 - -只有两种显示方式: - -1. **名称打码(默认)**:固定三个掩码符号加昵称最后一个字符,例如“和平”显示为“***平”。一个字符的昵称显示为“***”,不泄露原长度。 -2. **公开昵称**:显示 Google 账号昵称;未来接入 ZOPC 资料后可切换为 ZOPC 昵称。 - -如果账号没有可用昵称,使用系统生成的中性昵称,例如“脉冲用户 7K2P”,不额外要求用户填写资料。 - -用户加入后可以在排行榜右上角菜单切换名称显示方式,修改立即作用于当前榜单。 - -## 6. 登录与会话 - -首版只使用 Google 第三方登录,不提供邮箱密码,也不自建密码系统。 - -技术流程: - -1. App 使用系统浏览器打开 Google OAuth。 -2. 使用 state + PKCE + `127.0.0.1` 临时回调完成授权码交换。 -3. Google ID token 由 MacPulse 服务端验签;MacPulse 刷新令牌只存 macOS Keychain。 -4. UserDefaults、日志、网址参数和排行榜接口中不得出现长期令牌。 -5. 会话长期保持,避免用户频繁重复登录。 - -用户可感知的只有“使用 Google 登录并加入”;PKCE、令牌刷新和账号绑定都隐藏在后台。 - -## 7. 每日同步 - -登录成功后默认开启。客户端在本地扫描完成后按当前自然日幂等覆盖,最频繁不超过每 10 分钟一次: - - local_day - total_tokens - estimated_cost_micro_usd - pricing_version - app_version - -不上传: - -- 会话正文、提示词或回复内容 -- 模型、项目名、项目路径或 session ID -- Claude/Codex 凭证或任何第三方 API Key -- 系统进程、文件名或设备序列号 - -相同 user_id + local_day 使用幂等覆盖,重复请求不会重复累计。 - -## 8. 最小后台 - -首版后台只做一个页面中的三个区块: - -1. **概览**:排行榜成员数、当日同步人数、排行榜成员 DAU、D1/D7/D30 留存、App 版本分布。 -2. **公开榜单入口**:直接查看 Token 榜与费用榜。 -3. **用户管理**:加入时间、最后同步时间、显示模式和隐藏异常记录。 - -这些指标只代表“已登录并加入排行榜的用户”,不代表全部 MacPulse 用户。全部下载量继续看 GitHub Release;首版不再增加另一套匿名遥测开关。 - -管理员操作写入审计日志,后台启用多因素认证。 - -## 9. 最小数据模型 - - profiles - user_id - nickname - display_mode # masked / public - joined_at - left_at - consent_version - last_app_version - - daily_usage - user_id - local_day - total_tokens - estimated_cost_micro_usd - pricing_version - app_version - created_at - updated_at - - admin_audit - actor_id - action - target_id - created_at - -榜单从 daily_usage 聚合生成,不再额外维护一套可被写乱的“分数表”。 - -最小接口: - - GET /api/v1/rankings?metric=tokens&period=week - GET /api/v1/rankings/me - PUT /api/v1/me/daily-usage - PATCH /api/v1/me/display-mode - DELETE /api/v1/me/ranking - -## 10. 社区、知识库与 AI 服务预留 - -首版只在 MacPulse 设置中保留两个普通外链: - -- “打开 ZOPC 社区” -- “打开 ZOPC 知识库” - -不要求登录,不做 WebView,不同步阅读进度。未来官网可以复用同一个 ZOPC 账号实现会员内容和收藏,但不改变 MacPulse 的本地功能。 - -未来 AI 服务只预留 /api/v1/ai 命名空间和独立数据域,不在首版 App 中出现入口,也不接入生产模型密钥。供应商密钥只能存服务端 Secret/KMS,不能放进 MacPulse 或公开仓库。 - -## 11. 风险边界 - -- MacPulse 是开源客户端,排行数据可以被修改或伪造;首版只是社区展示,不提供现金、Token 或实物奖励。 -- 服务端做每日唯一键、合理数值上限、突增检测和人工隐藏,但不宣称榜单“不可作弊”。 -- 费用榜必须始终写“API 等价预估”,不能暗示真实账单。 -- 退出排行榜后立即停止上传并移除公开记录。 -- 隐私说明、加入面板和官网必须使用同一套上传字段描述。 - -## 12. 分期 - -### 0.10.0:最小闭环 - -- 一个排行榜入口。 -- 一个“Google 登录并加入”入口。 -- Token 周榜、费用周榜和我的排名。 -- 名称默认打码、可切换公开。 -- 每日聚合、退出排行榜和单页轻量管理后台。 - -### 0.11.0:官网连接 - -- ZOPC 社区和知识库稳定入口。 -- 官网复用 ZOPC 登录态。 -- 根据实际需求决定是否增加月榜或个人趋势。 - -### 以后 - -- 社区会员、知识库收藏和 AI 服务均在官网独立验证。 -- 不提前向 MacPulse 主界面增加入口、开关或账号设置。 - -## 13. 首版验收 - -- 首次启动、更新和本地功能没有登录提示。 -- 游客能浏览公开周榜,但不会上传任何数据。 -- 登录成功即加入 Token 榜和费用榜,无中间状态。 -- 加入面板一次讲清上传字段和名称显示。 -- 默认名称打码;只有用户主动选择才显示完整昵称。 -- 登录后立即能看到自己的两个名次。 -- 退出排行榜立即停止同步、移除公开记录并清除本机凭证。 -- 后台看不到会话正文、项目、路径、模型或第三方凭证。 -- 后台 DAU 与留存明确标注为排行榜成员口径。 -- 在线服务故障不影响任何本地监控功能。 - -## 14. 实施前只需确认 - -1. 在 Google Cloud 创建 Desktop OAuth Client 与 Web OAuth Client。 -2. 将官网域名加入 Web Client 的授权来源并完成 OAuth consent screen。 -3. 把两个 Client ID 与服务端会话密钥配置到生产环境,再做真账号端到端验收。 diff --git "a/docs/\345\217\221\345\270\203\346\214\207\345\215\227.md" "b/docs/\345\217\221\345\270\203\346\214\207\345\215\227.md" deleted file mode 100644 index 1d567b0..0000000 --- "a/docs/\345\217\221\345\270\203\346\214\207\345\215\227.md" +++ /dev/null @@ -1,140 +0,0 @@ -# MacPulse 官网分发指南 - -MacPulse 通过 GitHub Releases 发布 Developer ID 签名、Apple 公证的 DMG,官网提供固定 HTTPS 入口, -Sparkle 读取官网上的签名 appcast。不使用 Mac App Store,以保留 SMC 传感器与安全缓存清理功能。 - -公开 Beta 固定条件:Bundle ID `com.liangheping.macpulse`、Apple Silicon、macOS 14+。 - -## 1. 一次性准备 - -### Developer ID Application - -1. Xcode → Settings → Accounts,选中开发者账号。 -2. Manage Certificates… → `+` → Developer ID Application。 -3. 验证: - -```sh -security find-identity -v -p codesigning | grep "Developer ID Application" -``` - -把带私钥的证书导出为加密 `.p12`,私下异地备份。不要提交到 Git、Issue 或 CI。 - -### Apple 公证凭据 - -准备 Apple ID、Team ID 和 App 专用密码,存入本机钥匙串: - -```sh -xcrun notarytool store-credentials macpulse-notary \ - --apple-id 你的AppleID邮箱 \ - --team-id 你的TeamID \ - --password 你的App专用密码 - -xcrun notarytool history --keychain-profile macpulse-notary -``` - -### Sparkle EdDSA 密钥 - -Sparkle 2.9.4 的私钥保存在钥匙串,公钥在 `Config/SparklePublicKey.txt`。首次生成命令: - -```sh -.build/artifacts/sparkle/Sparkle/bin/generate_keys -``` - -只能有一把生产更新私钥。使用 `generate_keys -x` 导出私钥后,立即放入加密密码库或加密离线介质; -不要保存到项目目录,不要上传 GitHub Actions。丢失这把私钥会导致已安装用户无法验证后续更新。 - -## 2. 首次公开前的 Git 闸门 - -```sh -./scripts/preflight-release.sh -``` - -脚本会检查当前文件与待发布分支的全部可达 Git 历史中的密钥特征、私人绝对路径、内部会话/交接纪要, -同时要求工作区干净、必需开源文件存在且已配置 `origin`。如果旧提交命中,必须在首次推送前重写历史; -不能只删除 HEAD 文件。重写后再次扫描,并人工检查待推送文件清单。 - -首次公开前不要对未整理的本地 `main` 执行普通 push。 - -## 3. 版本与产物 - -构建接口始终同时接收语义版本和单调递增构建号: - -```sh -./scripts/build.sh 0.8.99 1 -./scripts/build.sh 0.9.0 2 -``` - -发布脚本: - -```sh -./scripts/release.sh 0.9.0 2 -``` - -流程为:构建 → Sparkle 嵌套组件由内向外签名 → 主 App Developer ID + Hardened Runtime + 时间戳 → -公证 App 并 staple → DMG 签名/公证/staple → SHA-256 → Sparkle EdDSA appcast。脚本不使用 `codesign --deep` -做签名,只用 `--deep` 执行最终嵌套验证。 - -产物: - -- `dist/MacPulse-0.9.0.dmg` -- `dist/MacPulse-0.9.0.dmg.sha256` -- `dist/appcast.xml` -- `release-notes/0.9.0.md` -- `dist/private/MacPulse-0.9.0-dSYM.zip` —— 私下保存,不上传 Release - -本地干跑: - -```sh -SKIP_NOTARIZE=1 ./scripts/release.sh 0.9.0 2 -``` - -干跑使用 ad-hoc 签名,只用于验证脚本,不得上传或分发。 - -## 4. 发布顺序 - -1. 部署下载站空壳,确定生产 appcast URL: - `https://macpulse-monitor.peaceaii.chatgpt.site/appcast.xml`。 -2. 建立干净发布提交,运行 `./scripts/test.sh` 与显式真实会话回归。 -3. 执行 `SKIP_APPCAST=1 ./scripts/release.sh 0.8.99 1`,构建、公证内测旧版,安装到 `/Applications`。 -4. 构建、公证 `0.9.0 / build 2`,创建暂不宣传的 GitHub Pre-release,上传与标签一致的产物。 -5. 将 `dist/appcast.xml` 部署到官网。appcast 中的 enclosure 必须是不可变的: - `https://github.com/hepinga/MacPulse/releases/download/v0.9.0/MacPulse-0.9.0.dmg`。 -6. 从签名的 0.8.99 执行手动检查与后台检查,确认安装、重启后为 0.9.0 (2)。 -7. 把 Pre-release 转为正式 Release,更新下载页 CTA、SHA-256 和更新记录。 - -appcast 生成后不得手工编辑。任何 URL、日期、说明或 enclosure 改动都必须重新运行发布脚本并签名。 - -## 5. 发布验收 - -```sh -shasum -a 256 -c dist/MacPulse-0.9.0.dmg.sha256 -hdiutil verify dist/MacPulse-0.9.0.dmg -xcrun stapler validate dist/MacPulse-0.9.0.dmg -spctl --assess --type open --context context:primary-signature -v dist/MacPulse-0.9.0.dmg -codesign --verify --strict --deep --verbose=2 dist/MacPulse.app -codesign -d --entitlements - dist/MacPulse.app -lipo -archs dist/MacPulse.app/Contents/MacOS/MacPulse -``` - -必须确认: - -- 只有 `arm64`,`LSMinimumSystemVersion` 为 `14.0`,版本/构建号正确。 -- App 和 DMG 的 Gatekeeper 结果为 accepted/notarized,DMG staple 有效。 -- 主 App 与 Sparkle helper/framework 嵌套签名有效,主 App 无 `get-task-allow`。 -- 浏览器下载 → 挂载 DMG → 拖入 Applications → 首次启动,不需要右键或关闭 Gatekeeper。 -- 未授权时不读 Claude 凭证、不弹通知权限;开启/关闭/拒绝/无凭证都可安全降级。 -- 手动检查、后台检查、EdDSA feed 和安装重启成功;篡改 DMG 或 appcast 后更新必须被拒绝。 - -最后邀请 3–5 名不同 M 系列用户试用 48–72 小时,覆盖 macOS 14、15、26。无安装阻断、 -数据安全问题和更新失败后再扩大公开传播。 - -## 6. 故障排查 - -公证失败时,使用 `notarytool submit` 输出的 submission id: - -```sh -xcrun notarytool log --keychain-profile macpulse-notary -``` - -若 Sparkle 拒绝更新,依次核对:旧新 App 的 Bundle ID、Developer ID Team ID、构建号单调性、 -`SUPublicEDKey`、appcast 整体签名、enclosure 的 EdDSA 签名/长度与实际 GitHub Release 资产。 diff --git "a/docs/\347\240\224\347\251\266\345\272\223/index.html" "b/docs/\347\240\224\347\251\266\345\272\223/index.html" deleted file mode 100644 index 35bc673..0000000 --- "a/docs/\347\240\224\347\251\266\345\272\223/index.html" +++ /dev/null @@ -1,326 +0,0 @@ -MacPulse 差异化调研库 - - -
-
-
MacPulse · 差异化调研库
-

怎么让它不再是"又一个 AI 用量工具"

-

14 个 UI / UX 维度的差异化弹药,外加一份行动手册。核心命题:整个赛道都是给工程师的折线图和 token 术语——MacPulse 要抢下"唯一给普通人的 AI 额度安心表",靠的是视觉语言、交互位置和情绪价值,而不是又一张仪表盘。

-
日期 2026-07-07方法 并行网页调研 + 设计领域综合覆盖 刘海生态 · 菜单栏视觉 · 氛围计算 · 情绪化设计 · 物理隐喻 · 游戏化 · 数据可视化 · 竞品空白 等 14 维
-
- - - - -

差异化行动手册综合

-

别在"信息量"上和竞品卷——它们已经赢了工程师。MacPulse 要赢的是那个不懂代码、怕账单、怕撞限的普通人。差异化不在"多一个图表",而在:把 token 翻译成人人会读的驾驶舱物理仪表、把刘海变成额度续航驾驶舱、给这个焦虑用户一个有温度的副驾。下面是能立住的支点。

- -
-

五个能立住的差异化支点

-
-
1

驾驶舱物理仪表(视觉护城河)

工作量 中

全赛道(ccusage / Stats / iStat)都是工程师的折线图 + 环形占比,人人雷同。MacPulse 独占普通人的物理仪表盘:油量表、沙漏、温度计、一盏灯。隐喻选择本身就是和所有监控类竞品的区隔——别人给数据,你给"一眼就懂的仪表"。

-
2

刘海 = 额度续航驾驶舱(独占位置)

工作量 低

竞品在菜单栏堆数字。MacPulse 把刘海做成 hover 下拉的"续航驾驶舱"——这是一个别人没占的物理位置 + 灵动岛式交互,基建已搭好(NotchShape/hover)。一个"持续进行的额度倒计时"天生就是 Live Activity 该待的地方。

-
3

有温度的"副驾"人格(情绪价值)

工作量 中

竞品全是冷冰冰的仪表盘。账单焦虑用户要的不是数据,是安心。给它一个副驾人格:正向框架("还能痛快写 4 小时"而非"已用 72%")、关键时刻提醒、重置时庆祝、可选会变表情的小伙伴。没人给这个用户做过陪伴。

-
4

"续航焦虑"翻译层(认知差异)

工作量 低

已用 72% 翻成 "还能聊约 40 轮 / 撑到今晚 9 点"(distance-to-empty)。Tesla / Ford 早证明:人对"还能干多远"的直觉远强于"还剩多少"。这一层认知翻译,让不懂技术的人瞬间懂——是最便宜的差异化。

-
5

30 秒懂它信它的首启(非技术门槛)

工作量 中

面向非技术用户的 onboarding + 隐私信任(读你的用量/花费),竞品没人做好。一句话讲清价值、权限说清"全本地不上传"、首启立刻显示你的额度制造"啊哈"时刻——把小白留下。

-
- -

推荐的视觉 + 交互签名:一条"驾驶舱 / 续航"主线

-

别东一个西一个。选定"驾驶舱续航"做贯穿一切的签名,让产品一眼认得出:

-
    -
  • 主角=一支带阻尼回摆的油量表指针 + "还能聊约 40 轮 / 撑到今晚 9 点"
  • -
  • 重置=一只真会漏沙的沙漏(连续流、见底加速泛红)
  • -
  • 超支=温度计水银逼近预算顶端由绿转红、轻微搏动
  • -
  • 菜单栏=一盏 RAG 灯(余光可读,形状颜色 > 数字)
  • -
  • 材质=玻璃打底 + 可选"拟物驾驶舱皮肤"(Liquid Glass 折射 + VU 表针),做出不撞脸的材质签名
  • -
  • 动效=全走真实物理:指针 overshoot 回摆、液面波纹、沙子连续流——物理真实 = 可信 + 情绪
  • -
- -

点子清单(按 惊艳度 ÷ 成本 排序)

-
- - - - - - - - - - - - - - -
点子档位为什么值
正向框架文案(全局)Quick Win"还能痛快写 4h" 替掉 "已用72%",一改就治焦虑
distance-to-empty 翻译Quick Win"还能聊约 40 轮",秒懂,零成本认知差异
菜单栏一盏 RAG 灯Quick Win余光可读的 ambient 状态,calm tech
数值阻尼滚动动效Quick Win.numericText + 弹簧,立刻显高级
油量表主角(自绘仪表)中招视觉护城河的核心,一眼区别于折线图
沙漏重置 + 温度计超支中招把抽象窗口/预算变成物理直觉
重置"满血复活"庆祝动效中招庆祝而非只报警,情绪记忆点
副驾人格 + 贴心文案系统中招温度=差异化,竞品全无
拟物"驾驶舱皮肤"大招吃 Liquid Glass 拟物回潮红利,记忆点
随状态变表情的小伙伴/桌宠大招陪伴感,但需克制、可关
streak / 成就体系大招黏性,但工具类慎用避免幼稚
- -
明确劝退(会显幼稚 / 廉价 / 撞脸): -
    -
  • 别堆多图表——那是工程师产品(iStat/ccusage 已占),你一堆折线就撞脸+丢定位。
  • -
  • 别用纯百分比 + 默认红色警报美学制造焦虑,那正好背离"安心表"的魂。
  • -
  • 桌宠/养成要极度克制且可关,做重了立刻从"高级工具"掉成"幼稚小玩意"。
  • -
  • 别纯抄系统 Liquid Glass 玻璃——不加自己的拟物材质就会和一堆 2026 app 撞脸。
  • -
  • 动效别过量:该有物理阻尼的地方精致,别处处弹跳,过度动效=廉价。
  • -
-
-
- - -

05 物理隐喻 / 拟物化仪表范式 · 已深挖

-

物理隐喻是给 vibe coder 的降维打击:把 token/额度/费用翻译成人人从小就会读的仪表。三问对应三个最直觉的隐喻——"还能用多久"用油量表 + 距离清空(Tesla/Ford 证明"还能跑多远"比"剩几升"更安心)、"多久重置"用实时下落的沙漏、"会不会超支"用会逼顶变红的温度计。iOS 26 Liquid Glass 带火的拟物回潮给了做"驾驶舱皮肤"的视觉红利。护城河:iStat 用工程师的折线图,MacPulse 反其道用普通人的物理仪表。

-
    -
  • 主隐喻锁定"油量表 + 距离清空":首页别写百分比,写"还能聊约 40 轮 / 撑到今晚 9 点"。Tesla 能耗 App、Ford Distance-to-Empty 都证明人对"还能跑多远"的直觉远强于"剩几升"。
  • -
  • 重置做成真会漏沙的沙漏:沙连续下落(不是数字跳),快见底时加速 + 沙堆泛红。参考 Minimal Hourglass——主打"小孩不识字也懂还要等多久"。
  • -
  • 反用 Apple Watch 圆环的 open loop:圆环快闭合本是"想凑满"的心理痒,MacPulse 要把它变成"红色缺口在逼近 = 该收手"的预警。
  • -
  • 花费用温度计做超支预警:借募捐温度计"越接近顶端越想完成"的心理反用——水银逼近预算顶端由绿转橙转红并轻微搏动,让"快超支"在余光里就有生理性紧张感。
  • -
  • 菜单栏用"一盏灯"(RAG):严守汽车仪表 glanceability 铁律——靠颜色和形状而非数字,让用户用余光就能读到安全/留意/危险。
  • -
  • 烧钱速度用速度表 = burn rate,配 "cash runway" 文案("按当前速度还能撑到 X 点")。
  • -
  • 所有动效走真实物理:表针带阻尼回摆(overshoot)、液面波纹、沙子连续流。物理真实感 = 可信 + 情绪价值。
  • -
-

为什么是降维打击

-

目标用户看不懂 token、context window、rate limit,但每个人都开过车、看过手机电量、等过沙漏。好隐喻把知识从熟悉领域"迁移"过来,让人瞬间获得"怎么读它"的直觉(Jakob Nielsen 的界面隐喻理论)。别教用户读数据,给他们一个从小就会读的仪表。

-

视觉红利:拟物回潮

-

iOS 26 的 Liquid Glass(WWDC 2025,macOS Tahoe 同步)把 skeuomorphism 拉回聚光灯——不是回皮革缝线,而是"用光的物理(折射、镜面高光)做真实感"。可抄的拟物配方:四层阴影(接触影/环境影/内高光/内暗部)、顶光渐变、letterpress 压印文字、按下 translateY(1px)、0.05 透明度噪点做表面颗粒。真实参考:Not Boring(付费"皮肤")、Halide(手势模拟物理拨盘)、Arturia V Collection(照片级复刻合成器 VU 表针)。

-
落到 MacPulse:主隐喻定为"驾驶舱油量表"(带阻尼回摆的指针 + 距离清空文案);重置=真沙漏;花费=温度计;菜单栏=一盏 RAG 灯;烧钱=速度表 + runway 文案;动效全走物理;出一个可选拟物驾驶舱皮肤做记忆点。隐喻选择本身就是和所有竞品的区隔。
- - -

01 刘海 / 灵动岛交互生态交互

-

NotchNook、Boring Notch、Alcove、DynamicLake、NotchDrop、MediaMate 这批 app 证明刘海能承载"非通知"的持续/hover 信息。最受欢迎的交互:媒体控制、AirDrop 拖拽暂存(NotchDrop)、hover 展开的紧凑信息、以及"从刘海本体 morph 长出"的动效。最大差评点:常驻挡内容、功能堆砌。机会:没人用刘海做"AI 额度续航"。

-
    -
  • hover 展开 + 灵动岛式左右紧凑态是 NotchNook/Alcove 的核心交互——MacPulse 的 hover 下拉方向对。
  • -
  • NotchDrop 的"拖文件到刘海暂存"是最受好评的实用交互;启发:未来能不能拖点什么到刘海(弱相关,先不做)。
  • -
  • 灵动岛 Live Activities 范式:一个"持续进行的活动(倒计时/进度)"最适合刘海——额度倒计时天生契合,这是别人没做的用法。
  • -
  • 动效必须"从刘海本体长出"而不是弹窗——已做(NotchShape 无缝衔接)。
  • -
  • 别学功能堆砌型(把天气/日历/电池全塞刘海),专注"额度续航"一件事更利落、更有记忆点。
  • -
  • 常驻挡内容是最大差评——MacPulse 的"平时藏、hover 才现"是正确取舍。
  • -
-
落到 MacPulse:把刘海定位成"额度续航驾驶舱",做成灵动岛式的持续活动(倒计时),而非又一个塞满信息的刘海面板。这是一个别人没占的位置 + 用法。
- - -

02 菜单栏 app 视觉差异化视觉

-

菜单栏空间极小,辨识度靠"活体感"——Stats 的实时迷你折线/环、iStat 的动态图标、One Thing 的纯文字待办、Ice/Bartender 的收纳。差异化在"动态字形/微型仪表 + 颜色"而非静态图标。

-
    -
  • Stats 的菜单栏迷你实时图表是它辨识度的来源;iStat 用会动的图标;One Thing 用文字占位——都在"动"。
  • -
  • 避免又一个静态 SF Symbol——用会变色的一盏灯 + 迷你油量环,一眼认出是你。
  • -
  • 点开的弹窗要脱离系统默认样式(自有玻璃/圆角/排版/驾驶舱视觉),延续品牌。
  • -
  • 颜色变化(RAG)承担 ambient 状态,比数字更快被余光读到。
  • -
-
落到 MacPulse:菜单栏 = 一盏会变色的灯 +(可选)迷你油量环;弹窗延续驾驶舱视觉,不用系统默认长相。
- - -

03 氛围计算 / Calm Technology范式

-

Calm Technology(Mark Weiser & John Seely Brown)——信息待在余光、需要时才进注意力中心。经典案例 Ambient Orb(一个会变色的球报股市涨跌)。原则:用颜色/呼吸传状态、平时安静、异常才凸显。MacPulse 的"平时藏、紧张探头"正是 calm tech。

-
    -
  • 余光可读:颜色和形状 > 数字,让人不停下手里的活也能感知状态。
  • -
  • 平时安静、异常才响:默认极简一盏灯,快撞限/过热才主动探头。
  • -
  • 渐进披露:一层给状态(灯/环),想看明细再 hover——天然防数据轰炸。
  • -
  • 状态用"呼吸/微动"而非弹窗打断(Ambient Orb 式的柔和变色)。
  • -
-
落到 MacPulse:把 calm tech 当铁律:默认极简、余光可读、细节 hover 才给、警告用柔和呼吸而非硬弹窗。
- - -

04 情绪化设计 / 焦虑缓解情绪

-

为焦虑用户设计。Don Norman 情绪化设计三层(本能/行为/反思)。钱焦虑的 fintech(Copilot Money、Monarch、Cleo 拟人化 AI)靠正向框架 + 掌控感 + 可预期来缓解。关键:别用红色恐吓,把"限制"讲成"节奏"。

-
    -
  • 正向框架:"还能痛快写 4 小时" ✅ 而非 "已用 72%" ❌——同一个数,情绪天差地别。
  • -
  • 避免默认红色/警报美学:默认绿色安心态,红色只留给真危险。
  • -
  • 可预期 = 掌控感:清晰的重置倒计时让人"知道什么时候能继续",焦虑就降了。
  • -
  • 庆祝而非只报警:额度重置做成"满血复活",给正反馈。
  • -
  • Cleo 式有温度的语气:让提示像朋友说话,不像系统报错。
  • -
-
落到 MacPulse:全局文案正向化;默认绿色安心;重置做庆祝;红色只在真危险时出现。这是"安心表"的魂。
- - -

06 游戏化 / streak / 桌面宠物游戏化

-

Duolingo 连胜、Forest/Finch 养成、Apple 圆环闭合、桌宠(Bongo Cat)。让"克制花费/规律使用"有黏性——但工具类做太重的养成会显幼稚。机会:一个随额度/花费/电脑状态变表情的极简"伙伴"。

-
    -
  • 轻量 streak(连续省钱天数、连续健康使用)可加,重养成慎用。
  • -
  • Apple 圆环闭合的成就感值得借,但要反用成"该收手"而非"凑满"。
  • -
  • 一个极简会变表情的吉祥物:开心 / 喘气(高负载)/ 发烫(过热)/ 满血(重置)——陪伴感强。
  • -
  • 避免 Tamagotchi 式重养成(会幼稚);桌宠必须默认关、可关
  • -
-
落到 MacPulse:做一个可选的极简"伙伴"(随额度/温度变表情),默认关;轻量成就点到为止,别做成小游戏。
- - -

07 单一指标的数据可视化数据可视化

-

把"一个百分比/一段倒计时/一个金额"呈现得又美又秒懂:Apple 活动圆环(金标准)、bullet chart、液面/波浪填充、径向仪表。主角(5h 倒计时)候选:油量表指针 / 液面下降 / 沙漏 / 圆环。

-
    -
  • Apple 活动圆环是单指标可视化的金标准——简洁、可动、可堆叠。
  • -
  • 液面/波浪填充有生命力(WaterLevel widget 类),比静态条更"活"。
  • -
  • bullet chart 表达"实际 vs 目标 vs 预测"三值(适合花费 vs 预算 vs 预估)。
  • -
  • 倒计时用连续动画非跳字;强调"当前值/端点"。
  • -
  • 避免饼图;颜色统一 RAG 编码。
  • -
-
落到 MacPulse:主角用"油量表指针 + 液面填充"组合,配阻尼动效;花费用 bullet(实际/预算/预估)。
- - -

08 顶级 Mac app 的设计签名视觉

-

Apple 设计奖获奖作 + 顶级 indie(Things、Fantastical、Craft、Halide、Bear、Reeder)。高级感来自:克制的配色、大留白、统一的圆角/图标语言、一个独特动效签名、精致排版、极致一致性。MacPulse 要有"作品感"必须定死一套签名。

-
    -
  • 一个强色 + 一套中性(建议琥珀/驾驶舱橙 + 暖中性),全局只用它。
  • -
  • 统一圆角、材质、图标语言;一个标志性动效(油量指针回摆)。
  • -
  • 大留白 + 严格字号层级;一致性 > 花样(Things 靠极致克制建立高级感)。
  • -
  • 图标要精致到能当"作品"(Halide/Reeder 的图标是记忆点)。
  • -
-
落到 MacPulse:定义设计签名 = 驾驶舱拟物材质 + 琥珀强调色 + 指针阻尼动效 + SF Rounded 数字,处处一致。
- - -

09 借 Apple 自家 glanceable 范式范式

-

Widgets、Live Activities、Control Center、Watch complications、StandBy——Apple 自己的 glanceable 视觉方言。借它们既原生又有辨识度。把额度做成 complication 式的圆环语言,用户零学习成本。

-
    -
  • Live Activities = 持续活动范式,额度倒计时天生契合(尤其在刘海)。
  • -
  • Watch complication 圆环语言:小、密、可堆叠——适合额度环。
  • -
  • Control Center 模块化磁贴 + Widget 分层信息:简单首页可借这套布局方言。
  • -
  • StandBy 大字夜间态:全屏"还能用多久"的沉浸模式点子。
  • -
  • 借系统范式 = 原生感 + 用户已有认知。
  • -
-
落到 MacPulse:简单首页借 Widget/complication 视觉方言;刘海用 Live Activity 范式。
- - -

10 非技术用户首启 + 信任情绪

-

给小白做首启:去术语、渐进引导、空状态、权限措辞、隐私信任(读你的用量/花费的顾虑)。参考 Raycast、Arc、Notion Calendar、各类 fintech。目标:30 秒让人懂它、信它、留下。

-
    -
  • 首屏一句话讲价值(不是功能列表):"随时知道 AI 还能用多久、别被账单吓到"。
  • -
  • 权限请求说清"为什么" + "全本地、不上传"的隐私承诺(读花费/额度最敏感)。
  • -
  • 制造"啊哈"时刻:首启立刻显示"你的"真实额度,而非空壳。
  • -
  • 专业模式渐进披露,别一上来吓退小白;全程大白话。
  • -
-
落到 MacPulse:加 3 屏首启:讲价值 → 要权限(说清本地隐私)→ 立刻显示你的额度。
- - -

11 竞品 UX 空白地图竞品

-

ccusage、Claude-Code-Usage-Monitor、tokscale、ccost、sniffly、Cursor 自带 dashboard、Helicone/Langfuse——全是开发者视角(终端表格、折线图、token 术语)。面向非技术用户几乎空白。没人做:物理隐喻、情绪价值、刘海、续航翻译、桌面陪伴。

-
    -
  • 别人做数据表/折线图 → 你做物理仪表
  • -
  • 别人满屏 token 术语 → 你做续航翻译("还能聊 40 轮")。
  • -
  • 别人是冷冰冰仪表盘 → 你有情绪陪伴/副驾人格
  • -
  • 别人在菜单栏/终端 → 你占刘海驾驶舱
  • -
  • 别人服务团队/FinOps → 你服务个人的安心
  • -
-
落到 MacPulse:把定位钉死为"唯一给普通人的 AI 额度安心表"——上面每一条差异化都从这个定位长出来,这就是护城河。
- - -

12 微交互 / 动效 / 声音交互

-

让人上瘾的微动效:数值滚动(.contentTransition(.numericText()))、弹簧、morph、粒子、状态转场、克制的声音(Things 的完成音)。名家 Rauno Freiberg、Emil Kowalski。关键时刻:刘海展开、额度变化、重置庆祝、警告。

-
    -
  • 数值滚动动画:金额/倒计时变化时滚动而非跳变,立刻显高级。
  • -
  • 刘海 morph 生长(已做)+ 重置"满血"粒子庆祝
  • -
  • 警告用呼吸;指针/液面用物理阻尼(overshoot 回摆)。
  • -
  • 声音可选、克制(重置一声轻响);hover 反馈要即时。
  • -
  • 全程尊重 reduce-motion
  • -
-
落到 MacPulse:给"刘海展开 / 额度变化 / 重置庆祝 / 警告"四个关键时刻各配一个精致物理动效,克制不廉价。
- - -

13 品牌 / 人格 / 文案语气品牌

-

工具靠人格建立记忆点:Cleo(毒舌理财 AI)、Duolingo 的 Duo、GitHub Octocat、Mailchimp Freddie。命名、语气、吉祥物、配色个性。让一个"监控工具"有温度、有记忆。

-
    -
  • 定一个人格:建议"副驾"——冷静、靠谱、关键时刻提醒你,不啰嗦。
  • -
  • 文案语气示例:把"额度已用 72%"写成"还能痛快写 4 小时,悠着点冲 🚗";把"额度已重置"写成"满血复活,继续!"。
  • -
  • 可选吉祥物承载人格(随状态变表情);语气全程一致。
  • -
  • 命名/配色要有个性;但避免过度耍宝(工具的可信度不能丢)。
  • -
-
落到 MacPulse:把人格定为"副驾",全部文案改成口语化的贴心陪伴;考虑一个极简吉祥物承载它。
- - -

14 2026 最新趋势 & Liquid Glass视觉

-

Apple 的 Liquid Glass(macOS 26)——用光的物理做真实感。2026 趋势:玻璃拟态回归、动态材质、空间感、AI 原生 UI、可变字体。MacPulse 受 SDK 15 限只能逼近,但要有自己的材质签名,别和一堆抄玻璃的 app 撞脸。

-
    -
  • .regularMaterial + 光边 overlay 逼近玻璃(已在做)。
  • -
  • 加自有"驾驶舱拟物材质"(仪表/表针/拨盘)做区隔——纯玻璃会撞脸。
  • -
  • 动态材质:hover 时折射高光移动;可变字体做数字的重量层级。
  • -
  • 拟物 + 玻璃混搭正是差异点:别人只有玻璃,你有玻璃里的仪表。
  • -
-
落到 MacPulse:玻璃打底 + 驾驶舱拟物皮肤 = 一个不撞脸的材质签名。
- - -
diff --git "a/docs/\350\260\203\347\240\224\346\212\245\345\221\212.html" "b/docs/\350\260\203\347\240\224\346\212\245\345\221\212.html" deleted file mode 100644 index b38e2ac..0000000 --- "a/docs/\350\260\203\347\240\224\346\212\245\345\221\212.html" +++ /dev/null @@ -1,382 +0,0 @@ -Token 监控台 · 调研报告 - - -
-
-
MacPulse · 调研报告
-

AI 编程工具的 Token 用量与花费监控

-

给「Token 监控台」的一次竞品与可行性摸底:市面成熟产品都在做什么、你想要的三个维度够不够、以及每个 AI 编程工具在你这台机器上到底能不能拿到真实 token。

-
- 日期 2026-07-06 - 方法 4 路并行调研 + 本机实地勘察 - 覆盖 10+ 开源工具 · 6 类商业产品 · 5 个本地数据源 -
-
- - -

TL;DR 五个核心结论

-
-
    -
  • 1你的三个维度是正确的地基,但不是省钱的关键。时间 / 工具 / 项目都是「分组」维度;真正决定能不能省钱的是「成本构成」维度——模型、token 类型、缓存命中率。模型单价跨档差 5–50 倍,四类 token 单价差 12 倍以上,不拆就算不对账。
  • -
  • 2Claude Code 与 Codex CLI 是最扎实的两条数据链路。都是纯本地文件、字段结构干净、含缓存与推理 token。Codex 的 ~/.codex/sessions 里有结构化的 total_token_usage 快照,可直接解析。
  • -
  • 3Cursor 能本地拿到真实 token,但拿不到官方美元账单。本机实测从 state.vscdb 聚合出约 1830 万 token(input/output 分开、含模型名与时间)。局限:无官方成本、历史覆盖偏近期、项目归属需推断。
  • -
  • 4Gemini CLI、GitHub Copilot 个人版本地拿不到 token。Gemini 默认不落盘;Copilot 只能走组织/企业 Metrics API(需管理员权限)。这两个工具维度要如实标注「本地不可得」。
  • -
  • 5成熟工具的差异化都在「实时」与「预测」。burn rate(消耗速率)、预测耗尽时间、5 小时计费块进度——把「已经花了多少」升级成「还能用多久、几点撞额度」,是最值得抄的范式。
  • -
-
- - -

01 竞品全景:四种流派

-

市面上的 AI 编程工具用量/成本监控,按「数据从哪来」可分为四类。个人本地场景(我们的定位)属于第一类,几乎都靠离线定价把 token 换算成等价美元。

-
- - - - - - - - -
流派数据来源代表产品适合谁
本地日志读取直接读本地会话 JSONL / SQLiteccusage · ccost · claude-code-costs · sniffly · tokscale · Claude-Code-Usage-Monitor个人开发者(← 我们)
代理拦截做中间人代理,自建 token 账本ccflare · CursorLens想要精确账本、愿改配置的人
厂商 API 治理拉厂商企业/组织 Metrics APIcursor-usage-tracker · copilot-metrics-viewer团队管理员 / FinOps
聚合 + 社交跨 40+ agent 聚合 + 排行榜tokscale爱分享、多工具混用的人
-
- -

值得深读的几个

-
    -
  • ccusage — 该生态事实标准。纯本地解析 Claude Code JSONL,daily/weekly/monthly/session/blocks 视图,按模型拆分,缓存 token 单列。它验证了我们想做的几乎所有维度都能从 JSONL 算出。
  • -
  • Claude-Code-Usage-Monitor — 当前最强实时预测:用 P90 百分位从历史自动推断你的限额,预测会话耗尽时间与撞额度 ETA。
  • -
  • ccost — 维度最细:group-by 到 day/hour/month/session/project/model/subagent/tool/line,还能算「每新增代码行成本」。
  • -
  • tokscale — Rust 内核跨 40+ agent,GitHub 式贡献日历 + 全球排行榜;token 拆到 input/output/cache 读写/reasoning 五类。
  • -
  • 商业侧(Langfuse / Helicone / Datadog) — 把「缓存」和「每请求成本」当一等公民;Datadog 允许把任意标签提升成成本 facet(启发我们留一个「自定义标签」口子)。
  • -
  • AWS Cost Explorer — 所有成本台的祖师爷:Service(≈模型)/ Usage Type(≈token 类型)/ Cost Category(≈项目标签)的 group-by 思路直接可映射。
  • -
- - -

02 数据源可行性矩阵 (本机实测)

-

「工具维度」能不能落地,取决于每个工具在本地到底存不存 token。我在你这台机器上逐个勘察了真实文件——结论差异很大。

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
工具本地能拿 Token?数据源能拿到什么本机实测
Claude Code已支持~/.claude/projects/**/*.jsonl四类 token · 模型 · 项目 · 会话 · 时间(最全)418 MB
Codex CLI最佳新增~/.codex/sessions/**/*.jsonlinput/cached/output/reasoning · 模型 · cwd 项目 · git · 时间272 MB · 76 会话
Cursor可行有局限state.vscdb (SQLite)input/output token · 模型名 · 时间 · 会话。无官方美元成本18.3M token
Roo Code格式支持·无数据task history 文件字段最全(含 totalCost + 缓存 + workspace),但本机无历史0 任务
Gemini CLI本地不可得~/.gemini(仅配置)默认不落盘 token,须开 OTEL 遥测才有20 KB
GitHub Copilot仅企业 APIGitHub Metrics API本地无 per-request token;官方需组织/企业管理员权限
-
-
可行性结论:一期把 Claude Code + Codex CLI 两条本地链路做扎实(纯读文件、离线定价、口径与 ccusage 对齐)。Cursor 作为二期第二数据源接入,并明确标注「token 为本地估算、非官方账单」。Roo 有数据的机器可用同一 schema 接入;Gemini / Copilot 标注为「本地不可得,需遥测或企业 API」。
- -
一个必须提前说清的口径坑:成本不在任何文件里——所有工具的美元金额都要靠「token 数 × 分模型分类型单价」自己乘,并维护一份可更新的定价表(LiteLLM + 官方页)。而且对 Claude/Codex 订阅用户,美元是「若走 API 会花多少」的名义值,真实约束是 5 小时块额度——两种口径不能混,否则用户会觉得数字对不上。
- - -

03 推荐维度体系

-

你已想到 时间 工具 项目 三个分组维度。基于竞品与数据可行性,下面这些是最值得补的——按优先级与可行性排序。P0 一期做,P1 二期,P2 视情况。

-
-
-

模型

P0
-

按 Opus/Sonnet/Haiku/Fable/GPT-5 等具体模型拆花费。单价跨档差 5–50 倍,是第一省钱杠杆——"贵活是不是都用了贵模型、能不能降档"。

-
可行性 · 每条记录直接带 model
-
-
-

Token 类型

P0
-

拆成 输入 / 输出 / 缓存写 / 缓存读 四类分别计价。四者单价差 12 倍以上,是成本的原子单位,不拆就算不对。

-
可行性 · usage 直接给四字段
-
-
-

缓存命中率

P0
-

cache_read /(input + cache 写 + cache 读)。唯一直接的省钱信号——命中率低往往是系统提示里有时间戳/UUID 在破坏前缀缓存。可派生"缓存已省 $X"。

-
可行性 · 四字段派生
-
-
-

会话 / 5 小时块

P0
-

会话=一次任务的天然单位("这次任务烧了多少")。5 小时滚动块=订阅额度的真实计量单位,Pro/Max 用户最该看的。

-
可行性 · sessionId + 时间分桶
-
-
-

Burn rate + 预算/预测

P0
-

近窗口 $/小时 或 token/分钟,叠加预算/额度,外推"本块几点用完、本月预估总额"。FinOps 核心告警,也是竞品最强差异化。

-
可行性 · 近段用量线性外推
-
-
-

最贵会话/请求 Top N

P1
-

成本长尾——少数超大上下文/超长输出吃掉大头。用直方图看分布 + Top N 表定位可优化点。

-
可行性 · requestId + usage
-
-
-

时段热力图

P1
-

小时 × 星期分桶,看"什么时段烧得最多",避开额度紧张时段、发现异常突增。

-
可行性 · 时间戳分桶
-
-
-

上下文体量

P1
-

每请求输入侧总 token,发现"上下文越滚越大"的会话并提示压缩。缓存失效之外的另一大成本源。

-
可行性 · usage 求和
-
-
-

效率单位经济

P2
-

每会话成本 / 每千行改动代码成本。把"花了多少"变成"值不值"。每千行需解析 transcript 里 Edit/Write 的增删行数。

-
可行性 · 需解析 tool_use
-
-
-

工具调用维度

P2
-

按 Bash/Read/Edit/WebFetch/MCP 拆"哪些工具在推高成本"(大 tool_result 灌入大量输入 token)。

-
可行性 · 需归因 tool_result
-
-
-

git 分支 / 子目录

P2
-

比项目更细,"这个 feature 花了多少"。cwd 一直有,gitBranch 仅较新版本记录,缺失降级到项目。

-
可行性 · 部分会话缺 branch
-
-
-

计费模式切换

P2
-

区分"订阅额度覆盖(名义美元)"与"API 按量真金白银"。两种口径切换,避免误导订阅用户。

-
可行性 · 需用户开关判定
-
-
- - -

04 可视化选型(有据可依)

-
- - - - - - - - - - - -
要表达什么用什么图为什么
时间趋势折线 / 堆叠面积连续时间上的量,面积可叠 token 类型构成
随时间的构成堆叠柱(离散日/周)每天的四类 token 或各模型占比
单快照占比甜甜圈(≤5 类)/ 堆叠条类别多别用饼,改堆叠条更易读
Top N / 明细可排序表 + 条形 + 条件着色最贵会话、按项目排名
额度 / 预算进度环 / 子弹图actual vs budget vs forecast 三值对比
时段规律小时 × 星期 热力图一眼看出高峰时段
单次成本分布直方图成本长尾、定位异常大请求
-
- - -
- - diff --git "a/docs/\350\277\275\345\212\240\351\234\200\346\261\202.md" "b/docs/\350\277\275\345\212\240\351\234\200\346\261\202.md" deleted file mode 100644 index 37aeb85..0000000 --- "a/docs/\350\277\275\345\212\240\351\234\200\346\261\202.md" +++ /dev/null @@ -1,41 +0,0 @@ -# 用户追加需求(写进 PRD 的「显示设置 / 计量单位」) - -## 1. Token 计量单位可切换(用户自选) -- **中文单位**:100 万 / 1000 万 / 1 亿(更符合中文用户直觉) -- **国际单位**:K / M(百万)/ B -- 默认:中文单位(用户是中文用户) -- 作用范围:所有展示 token 数量的地方(菜单栏、面板、图表轴、明细) - -## 2. 金额货币可切换 -- **美金 $**(原始计价单位) -- **人民币 ¥**(按汇率换算) -- 需要 USD→CNY 汇率:提供默认值(约 7.2,可编辑),可选联网自动获取(app 本身可联网,与 Artifact 无关) -- 默认:可先给人民币(中文用户),或跟随系统区域 - -## 3. 设置项:「计量单位」选项组 -放在监控台的设置/齿轮里,含: -- Token 单位:中文单位 / M(百万)/ 自动 -- 货币:¥ 人民币 / $ 美金 -- (可选)汇率手动填写 - -## 4. UI 必须符合 macOS 最新设计规范(用户说 macOS 27),含微交互/微动效 -- 目标:Liquid Glass 设计语言(macOS 26 Tahoe 引入,27 延续):半透明玻璃材质、动态高光、圆角、 - 层次模糊、内容自适应着色 -- 微交互:hover 高亮、按压反馈、选中态过渡、tab 切换动画 -- 微动效:数值变化的弹簧动画、图表入场、扫描/清理进度的流畅过渡、菜单栏图标平滑更新 -- **SDK 约束(关键)**:本机只有 CLT(SDK 最高 MacOSX15.2),无完整 Xcode。 - 真正的 Liquid Glass API(`.glassEffect()` 等,macOS 26 SDK 引入)编译不了。 - 两条路: - - A. 装 Xcode 26/27(App Store,~15GB,顺带修好损坏的 CLT)→ 可用真 Liquid Glass API + macOS 26/27 SDK - - B. 用 SDK 15 的 SwiftUI 逼近(.regularMaterial/.ultraThinMaterial 玻璃材质、模糊、 - spring 动画、hover/press 微交互、matchedGeometry 转场)→ 视觉接近 8 成,当前工具链即可 -- 默认先按 B 落地(不阻塞),用户若要 100% 保真再走 A -- **用户已决策(2026-07-06):选 B——用当前工具链(SDK 15 SwiftUI)逼近最新设计,不装 Xcode。** - 实现要点:全局改用 .ultraThinMaterial/.regularMaterial 玻璃背景 + 圆角卡片化区块 + - spring 数值动画(.animation(.spring, value:))+ hover 高亮 + 按压缩放 + tab matchedGeometry 转场 + - 图表入场动画 + 菜单栏数值平滑过渡。整体走浅色玻璃质感、层次分明、留白充足的 Tahoe 风格。 - -## 落地要点 -- 已有 `ByteFormat.tokens()` 目前输出 K/M/B,需扩展为支持中文单位模式 -- 金额格式化目前写死 `$`,需抽象成货币格式化函数,读全局设置 -- 设置用 @AppStorage 持久化(UserDefaults),全局生效 diff --git a/release-notes/0.10.0.md b/release-notes/0.10.0.md deleted file mode 100644 index aeb5b1d..0000000 --- a/release-notes/0.10.0.md +++ /dev/null @@ -1,24 +0,0 @@ -# MacPulse 0.10.0 Public Beta - -这一版加入轻量社区排行榜。Google 登录完全可选,不登录时所有本地功能仍可正常使用。 - -## 新功能 - -- Google 登录成功后自动加入 Token 消耗与 API 等价费用两个本周榜单 -- 默认打码昵称,只保留最后一个字符;可自愿公开完整昵称 -- 登录用户可查看自己的两个名次、立即同步或退出排行榜 -- 游客无需登录即可浏览官网与 App 内公开榜单 -- 新增官网隐私页与仅管理员可见的轻量运营后台 - -## 隐私与安全 - -- 仅同步上海时区每日 Token 总量、API 等价费用、价格表版本和 App 版本 -- 不上传会话正文、提示词、回复、项目名、路径、模型明细、AI 凭证或设备信息 -- 登录令牌只保存在 macOS Keychain -- 退出排行榜会停止同步,并删除每日榜单数据和服务端刷新会话 - -## 已知边界 - -- 仅支持 Apple Silicon 与 macOS 14+ -- 排行榜数据来自用户本地汇总,Beta 阶段以异常隐藏和人工反馈处理明显异常 -- Claude 额度仍依赖实验性接口,失效时不会影响其他功能 diff --git a/release-notes/0.8.99.md b/release-notes/0.8.99.md deleted file mode 100644 index 9fdc080..0000000 --- a/release-notes/0.8.99.md +++ /dev/null @@ -1,7 +0,0 @@ -# MacPulse 0.8.99 Internal Update Test - -仅用于验证从已签名、已公证旧版通过 Sparkle 更新到 0.9.0。 - -- Apple Silicon -- macOS 14+ -- 不对外发布,不生成公开 appcast 条目 diff --git a/scripts/check-release-prerequisites.sh b/scripts/check-release-prerequisites.sh index 9d06eeb..4e9584a 100755 --- a/scripts/check-release-prerequisites.sh +++ b/scripts/check-release-prerequisites.sh @@ -45,7 +45,7 @@ fi if (( failures > 0 )); then echo "" >&2 - echo "发布前置尚有 ${failures} 项待完成。请按 docs/Gatekeeper操作清单.md 处理。" >&2 + echo "发布前置尚有 ${failures} 项待完成。请按维护者私有发布手册处理。" >&2 exit 1 fi diff --git a/scripts/release.sh b/scripts/release.sh index 8893409..f3fe19c 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -49,7 +49,7 @@ if [ -z "${IDENTITY}" ]; then echo "==> 无 Developer ID 证书,干跑模式使用 ad-hoc 签名" else echo "错误:钥匙串中没有 Developer ID Application 证书。" >&2 - echo "请按 docs/发布指南.md 完成证书和 macpulse-notary 配置。" >&2 + echo "请按维护者私有发布手册完成证书和 macpulse-notary 配置。" >&2 exit 1 fi else diff --git a/tests/MacPulseTests/CoreRegressionTests.swift b/tests/MacPulseTests/CoreRegressionTests.swift index f42f010..906a2c0 100644 --- a/tests/MacPulseTests/CoreRegressionTests.swift +++ b/tests/MacPulseTests/CoreRegressionTests.swift @@ -234,7 +234,7 @@ final class CoreRegressionTests: XCTestCase { } func testPrivacyAliasIsStableAndDoesNotLeakProjectName() { - let raw = "-Users-liangheping-Documents-Secret-Client" + let raw = "-Users-example-Documents-Sample-Project" let first = ProjectName.display(raw, privacy: true) XCTAssertEqual(first, ProjectName.display(raw, privacy: true)) XCTAssertNotEqual(first, ProjectName.display(raw, privacy: false)) @@ -452,7 +452,7 @@ final class CoreRegressionTests: XCTestCase { } func testRankingNicknameDefaultsToFixedMask() { - XCTAssertEqual(RankingProfile.masked("和平"), "***平") + XCTAssertEqual(RankingProfile.masked("示例用户"), "***户") XCTAssertEqual(RankingProfile.masked("A"), "***") XCTAssertEqual(RankingProfile.masked(""), "***") } diff --git a/website/.gitignore b/website/.gitignore index 236cfc6..46cbac5 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -40,3 +40,6 @@ next-env.d.ts /.wrangler/ /outputs/ /work/ + +# Local hosting project metadata; keep account-level IDs out of the public repo. +/.openai/ diff --git a/website/.openai/hosting.json b/website/.openai/hosting.json deleted file mode 100644 index c13ac6e..0000000 --- a/website/.openai/hosting.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "project_id": "appgprj_6a599c457e8c8191b66c966ed83ca95d", - "d1": "DB", - "r2": null -} diff --git a/website/README.md b/website/README.md index 192ed5f..9b20b40 100644 --- a/website/README.md +++ b/website/README.md @@ -6,13 +6,12 @@ MacPulse 公开 Beta 的固定 HTTPS 下载入口,使用 vinext 和 Sites 托 - 下载页:`app/page.tsx` - 公开榜单:`app/rankings/page.tsx`(无需登录) - 隐私说明:`app/privacy/page.tsx` -- 轻量后台:`app/admin/page.tsx`(仅 `ADMIN_EMAILS` 白名单) - API:`worker/api.ts` - D1 迁移:`drizzle/0001_rankings.sql` - 样式:`app/globals.css` - Sparkle feed:`public/appcast.xml` -排行榜仅存用户标识、名称显示方式、上海时区每日总 Token、费用汇总、价格表版本与 App 版本。不会存会话正文、项目名、路径、模型明细或第三方 AI 凭证。后台的用户数、DAU 与留存都只代表已加入排行榜的成员,不代表全部 MacPulse 用户。 +排行榜仅存用户标识、名称显示方式、上海时区每日总 Token、费用汇总、价格表版本与 App 版本。不会存会话正文、项目名、路径、模型明细或第三方 AI 凭证。 ## 本地验证 diff --git a/website/tests/worker-api.test.ts b/website/tests/worker-api.test.ts index c4e8d56..a9187a3 100644 --- a/website/tests/worker-api.test.ts +++ b/website/tests/worker-api.test.ts @@ -87,7 +87,7 @@ function env(db?: FakeDB, overrides: Partial = {}): Env { } test("masks every nickname to a fixed prefix and final character", () => { - assert.equal(maskNickname("和平"), "***平"); + assert.equal(maskNickname("示例用户"), "***户"); assert.equal(maskNickname("A"), "***"); assert.equal(maskNickname(""), "***"); }); @@ -115,7 +115,7 @@ test("Google app login automatically joins with a masked profile", async () => { body: JSON.stringify({ id_token: "verified-by-test", app_version: "0.10.0 (3)" }), }), env(db), - async () => ({ subject: "google-123", email: "person@example.com", name: "和平" }), + async () => ({ subject: "google-123", email: "person@example.com", name: "示例用户" }), ); assert.equal(response?.status, 200); const body = await response?.json() as { @@ -127,7 +127,7 @@ test("Google app login automatically joins with a masked profile", async () => { assert.equal(typeof body.refresh_token, "string"); assert.equal(body.profile.id, db.profile?.id); assert.equal(body.profile.display_mode, "masked"); - assert.equal(body.profile.name, "***平"); + assert.equal(body.profile.name, "***户"); assert.equal(db.profile?.left_at, null); assert.equal(db.refreshSessionCount, 1); }); diff --git a/website/tests/worker-lifecycle.test.ts b/website/tests/worker-lifecycle.test.ts index 21f124f..8dc65b7 100644 --- a/website/tests/worker-lifecycle.test.ts +++ b/website/tests/worker-lifecycle.test.ts @@ -89,7 +89,7 @@ async function login(db: SQLiteDB, subject = "google-person") { body: JSON.stringify({ id_token: "verified-by-test", app_version: "0.10.0 (3)" }), }), env(db), - async () => ({ subject, email: `${subject}@example.com`, name: "和平" }), + async () => ({ subject, email: `${subject}@example.com`, name: "示例用户" }), ); assert.equal(response?.status, 200); return await response?.json() as { @@ -113,7 +113,7 @@ test("public ranking stays readable without login and protects masked names", as const now = new Date().toISOString(); db.raw.exec(` INSERT INTO profiles VALUES - ('p1', 's1', 'one@example.com', '和平', 'masked', '${now}', NULL, NULL, 'v1', '0.10.0', '${now}', '${now}'), + ('p1', 's1', 'one@example.com', '示例用户', 'masked', '${now}', NULL, NULL, 'v1', '0.10.0', '${now}', '${now}'), ('p2', 's2', 'two@example.com', '公开用户', 'public', '${now}', NULL, NULL, 'v1', '0.10.0', '${now}', '${now}'); INSERT INTO daily_usage VALUES ('p1', '${day}', 200, 3000000, 'test', '0.10.0', '${now}', '${now}'), @@ -128,7 +128,7 @@ test("public ranking stays readable without login and protects masked names", as entries: Array<{ rank: number; name: string; value: number }>; }; assert.deepEqual(body.entries, [ - { rank: 1, name: "***平", value: 200 }, + { rank: 1, name: "***户", value: 200 }, { rank: 2, name: "公开用户", value: 100 }, ]); assert.equal(JSON.stringify(body).includes("@example.com"), false); diff --git a/website/vite.config.ts b/website/vite.config.ts index ae08f93..536bb01 100644 --- a/website/vite.config.ts +++ b/website/vite.config.ts @@ -1,12 +1,12 @@ import vinext from "vinext"; import { defineConfig } from "vite"; -import hostingConfig from "./.openai/hosting.json"; import { sites } from "./build/sites-vite-plugin"; const SITE_CREATOR_PLACEHOLDER_DATABASE_ID = "00000000-0000-4000-8000-000000000000"; -const { d1, r2 } = hostingConfig; +const d1 = process.env.MACPULSE_D1_BINDING ?? "DB"; +const r2 = process.env.MACPULSE_R2_BINDING ?? null; // macOS Seatbelt blocks FSEvents, so Codex previews need polling for HMR. const isCodexSeatbeltSandbox = process.env.CODEX_SANDBOX === "seatbelt";