配置、环境与状态设计¶
状态:设计提案
ChatPost 0.1.x 已读取 task-specific [zhihu] / [csdn] Runner TOML 和权限 0600 的 bridge env 文件;本页其余通用 Runner/Account/ledger schema 仍是提案。
设计结论¶
ChatPost 不应该把所有内容塞进 .env。配置分成四类:
- 机器依赖与版本化制品:Playwright package/browser 由 ChatUp 管理,浏览器 Profile metadata 由 ChatBrowser 管理,扩展由 ChatPost/adapter 管理;
- 非秘密配置:Runner、Account、端口策略和路径引用;
- 秘密:每个 bridge/远端 Runner 的 token,放 ChatEnv;
- 运行状态与业务台账:进程健康状态和 publication ledger,分别持久化。
Cookie、Local Storage、密码和验证码不属于任何 ChatPost 配置层。
文件布局¶
用户级 ChatArch Home¶
~/.chatarch/
├── playwright/ # ChatUp-owned Playwright backend
│ └── <playwright-version>/{package,browsers,installation.json}
└── chatpost/
├── config.toml
├── extensions/
│ └── wechatsync/<version>/...
├── runners/
│ └── <runner>/
│ ├── runner.toml
│ ├── chrome-data/ # mode 0700,包含浏览器登录态
│ ├── state.json # 非秘密 runtime state
│ ├── run/
│ └── logs/
├── accounts.toml
└── logs/
内容 workspace¶
<workspace>/.chatpost/
├── config.toml # source/target 默认值,可选
└── publications.sqlite3 # source-to-target ledger
Chrome installation 是 ChatUp 机器级资源;Profile 是 ChatPost Runner 状态;文章映射是 workspace 级状态。三者分开,避免把可移动内容仓库与某台机器或登录态绑定。
当前已实现的登录基础层默认使用 ~/.chatarch/chatpost/ 作为 ChatArch-owned state root:CHATPOST_HOME 可覆盖 state root,CHATPOST_ACCOUNT_REGISTRY 或 CLI --registry PATH 可覆盖 registry 文件;默认 registry 是 ~/.chatarch/chatpost/accounts.toml。普通用户不需要在仓库根目录、当前工作目录或临时 project 目录放 accounts.toml。
ChatUp Playwright dependency¶
ChatPost 通过已发布的有界依赖消费 ChatUp 与 ChatBrowser:
环境准备由 ChatUp 独立完成:
ChatPost 启动 Runner 时只调用 chatup.playwright.resolve(...):读取 Playwright version、browser revision/version、binary path、package/browser roots 与 Node version。它不调用安装 API,不保存另一份 browser registry,也不下载浏览器。descriptor 缺失或版本不兼容时 fail closed,并提示运行 chatup playwright install <chatpost-tested-version> --browser chromium。
ChatBrowser Profile metadata dependency¶
ChatBrowser 管 browser backend、Profile metadata 与 CDP session registry。ChatPost 配置只引用它,不复制浏览器 registry:
[zhihu]
browser_profile = "zhihu-test"
profile_dir = "/home/zhihong/.chatarch/chatpost/profiles/test/zhihu"
[csdn]
browser_profile = "csdn-test"
profile_dir = "/home/zhihong/.chatarch/chatpost/profiles/test/csdn"
browser_profile 通过 chatbrowser.registry.profile_path() 解析;如果同时保留 profile_dir,必须和 ChatBrowser registry 中的路径一致。ChatPost 仍拥有平台账号 alias、platform/profile 映射、Wechatsync extension/bridge/env/receipt 字段;ChatBrowser 不判断“登录了哪个平台账号”,也不创建草稿。
chatbrowser profile create zhihu-test \
--path "$HOME/.chatarch/chatpost/profiles/test/zhihu" \
--backend chatup-playwright \
--label owner=chatpost \
--label platform=zhihu \
--label logical_profile=test \
--output json
chatbrowser profile show zhihu-test --output json
chatbrowser profile create csdn-test \
--path "$HOME/.chatarch/chatpost/profiles/test/csdn" \
--backend chatup-playwright \
--label owner=chatpost \
--label platform=csdn \
--label logical_profile=test \
--output json
chatbrowser profile show csdn-test --output json
非秘密配置示例¶
当前可读的 task-specific TOML 见 CLI 树;以下通用 registry TOML 仍是预期 schema:
schema_version = 1
[runners.zhihu-personal]
runtime = "host"
visible = true
profile_mode = "managed"
attach_existing_cdp = false
[runners.zhihu-personal.cdp]
bind = "127.0.0.1"
port = "auto"
[runners.zhihu-personal.bridge]
mode = "managed"
ws_bind = "127.0.0.1"
ws_port = "auto"
control_transport = "stdio"
token_profile = "zhihu-personal"
[accounts."zhihu@personal"]
platform = "zhihu"
runner = "zhihu-personal"
attach_existing_cdp = false 是默认值:ChatPost 启动并拥有一个 browser process,结束时通过启动时捕获的 browser CDP endpoint 关闭它。如果一个已知 browser 已经持有该 Profile 且暴露 loopback CDP,可设置 attach_existing_cdp = true 并让 cdp_port 指向现有 endpoint。attach 模式只创建/关闭本次 extension popup,保留现有 browser 运行,并在 receipt 中记录 cleanup_status=LEFT_RUNNING_EXISTING_CDP。
ChatEnv 只存秘密¶
每个 Runner 使用独立 ChatEnv profile。首版需要的生产字段:
| 字段 | 类型 | 用途 |
|---|---|---|
CHATPOST_BRIDGE_TOKEN |
sensitive | ChatPost CLI 与该 Runner 扩展 bridge 的控制通道鉴权。 |
CHATPOST_REMOTE_RUNNER_TOKEN |
sensitive / later | 未来远端 Runner 的注册或 transport 鉴权。 |
当前脚手架的 CHATPOST_API_KEY 不代表知乎或 bridge 凭据;实现时应删除或替换这个没有业务语义的占位字段。
Runner 非秘密配置只保存 profile 名称,例如:
ChatEnv 是 token 的 canonical source。为了让扩展验证 RPC,Runner 在证明 exact extension identity 后,把同一个 runner-scoped token 写入该扩展自己的 chrome.storage.local。这个 Profile 内副本仍是秘密,但不是知乎 Cookie;轮换必须同时更新 ChatEnv 和扩展副本,任何一侧失败都让 Runner 退出 READY。
这是 ChatPost 的新 ownership 提案,不是对旧实践的描述。已验证原型由扩展生成随机 token,再由受控脚本把同一值写入权限 0600 的 .env。正式实现如果改为 ChatEnv 生成/托管 canonical value,必须增加原子 provision/rotation 测试;不能假设现有扩展已经支持这个方向。
读取优先级遵循 ChatArch 约定:
config show 只能显示 profile 名称、key 名称和是否已配置,不能显示 token 值或掩码尾部。
URL 与端口¶
Managed local Runner¶
用户不应填写 URL。ChatPost 分配端口并在启动后派生:
cdp_url = http://127.0.0.1:<debug-port>
bridge_ws_url = ws://127.0.0.1:<bridge-port>
control = stdio
cdp_url只给 Runner manager;bridge_ws_url写入 exact extension 配置,由扩展主动连接 bridge server;- ChatPost adapter 默认通过 in-process/stdio 调用 bridge process;
- 如果需要 companion HTTP,它使用单独端口并同时满足 loopback 与 control authentication,不能只依赖“在本机”;
- 端口租约写 runtime state,不写 publication ledger。
Runner 配置扩展时只能写 bridge URL、token 和 enable flag 这些扩展自有字段。实现必须先证明 exact extension identity,不能读取或修改知乎页面的 Cookie/Local Storage。无法安全自动配置时,Runner 进入 NEEDS_EXTENSION_SETUP 并打开扩展设置页让用户处理。
Adopt existing Profile¶
为了迁移已经登录的 Profile,Runner 可以按引用接管:
ChatPost 不复制、不压缩、不检查 Cookie 内容。第一次 start 前必须确认该目录未被其他 Chrome 进程占用,并把目录权限与所有权纳入 doctor。
External Runner¶
未来外部 Runner 暴露独立 control API,而不是 extension WebSocket:
[runners.remote-brand.control]
transport = "https"
url = "https://runner.example.invalid/v1"
token_profile = "remote-brand"
外部 control URL 必须使用受控 tunnel/VPN 或 TLS+认证;不能把本地 extension WebSocket、CDP 或 companion HTTP 直接映射到公网。
Runtime state¶
runners/<name>/state.json 只保存可重建、非秘密状态:
{
"state": "READY",
"pid": 12345,
"chrome_provider": "chatup",
"chrome_ref": "chrome-for-testing@<resolved-version>",
"chrome_binary_path": "<resolved-path>",
"cdp_port": 9227,
"bridge_port": 9527,
"control_transport": "stdio",
"extension_id": "<verified-id>",
"extension_protocol": "<version>",
"started_at": "<timestamp>",
"last_heartbeat_at": "<timestamp>"
}
PID 不能单独证明身份。runner stop 还必须匹配 user-data-dir、binary、Runner owner marker 或服务单元。
当前 Wechatsync request/response message schema 没有协商 protocol version。extension_protocol 是 ChatPost 的待实现门禁:可以通过显式 handshake,或由 compatibility manifest 证明 exact bridge/extension artifact pair。在两者都没有之前必须报告 PROTOCOL_UNVERIFIED,不能伪报版本兼容。
Account registry¶
当前已实现的 accounts.toml 保存非秘密 Profile metadata 和 runner config 引用;默认位置是 ~/.chatarch/chatpost/accounts.toml:
[accounts."zhihu-personal"]
platform = "zhihu"
runner_config = "runners/zhihu-personal/runner.toml"
profile = "zhihu-personal"
label = "Personal Zhihu browser Profile"
login_methods = ["qr"]
[accounts."xhs-personal"]
platform = "xhs"
runner_config = "runners/xhs-personal/runner.toml"
profile = "xhs-personal"
label = "Personal XHS browser Profile"
login_methods = ["qr"]
[accounts."csdn-personal"]
platform = "csdn"
runner_config = "runners/csdn-personal/runner.toml"
profile = "csdn-personal"
label = "Personal CSDN browser Profile"
login_methods = ["qr"]
相对 runner_config 路径按 registry 所在目录解析,因此默认会落在 ~/.chatarch/chatpost/runners/...。它不保存用户名、手机号、密码、Cookie、LocalStorage、IndexedDB、session、token 或验证码。平台返回的公开 display name 只能作为诊断结果,不应成为目标主键。
Publication ledger¶
建议首版使用 SQLite,至少包含:
source_ref
source_sha256
target # platform@alias
runner
operation # create_draft / update_draft
draft_id / article_id
review_url / public_url
adapter_version
browser_version
extension_protocol
status
receipt_json_redacted
created_at / updated_at
唯一约束应等价于:
Token、Cookie、请求头、Profile 内容和一次性登录材料永远不进入 ledger。
配置优先级¶
command options
> workspace .chatpost/config.toml
> user ~/.chatarch/chatpost/config.toml
> built-in safe defaults
秘密不参与这个普通配置合并,而是通过明确的 ChatEnv profile 解析。这样 config validate 可以在不读取秘密值的情况下检查引用是否存在。
旧 Wechatsync 实践迁移表¶
| 旧字段/状态 | ChatPost 资源 |
|---|---|
WECHATSYNC_CHROME_BIN |
ChatUp PlaywrightBrowserInstallation.binary_path;Runner 启动时只读解析。 |
WECHATSYNC_CHROME_PROFILE |
Runner user_data_dir;默认 managed,也可 adopt 现有目录。 |
WECHATSYNC_DEBUG_PORT |
Runner CDP lease;默认 auto。 |
extension serverUrl / SYNC_WS_PORT |
Runner bridge_ws_url / WebSocket port lease;扩展主动连接。 |
SYNC_HTTP_PORT |
可选 companion control endpoint;ChatPost managed local 默认改用 stdio。 |
WECHATSYNC_TOKEN |
Runner 对应 ChatEnv profile 的 CHATPOST_BRIDGE_TOKEN。 |
.env 中的登录辅助信息 |
不迁移;平台登录由可见浏览器人工完成。 |
state/publication-state.json |
workspace publication ledger。 |
迁移不是复制 .env 或 Profile。它是先由 ChatUp 提供 Chrome dependency,再建立 Runner、Account 和 Publication 三种 ChatPost 资源的映射。
权限与备份¶
chrome-data/:目录权限0700;不自动备份、不进入 Git。- ChatEnv secret profile:由 ChatEnv 负责文件权限、写入和脱敏。
state.json:不含秘密;写入采用原子替换。publications.sqlite3:包含草稿 URL/ID 等敏感元数据,应按用户数据保护。- logs:默认过滤 URL query、headers、Cookie、Token 和二维码内容。
Schema 验证¶
提案中的 config validate / doctor 至少检查:
- 已安装
chatup>=0.2.12,<0.3.0和chatbrowser>=0.1.5,<0.2.0,且 ChatPost 兼容版本可由chatup.playwright.resolve解析并执行;验证过程不触发安装; - Runner 名称、Profile 路径和端口租约唯一;
- CDP/bridge bind address 为 loopback,本地 control transport 默认 stdio;
- token profile 引用存在但不读取/打印值;
- Account 指向存在的 Runner 和 adapter;
- 同一 user-data-dir 没有被两个 Runner 引用;
- workspace ledger schema 可迁移且未损坏。