asmgr 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +90 -10
  2. package/dist/asmgr.mjs +4954 -1070
  3. package/package.json +3 -2
package/README.md CHANGED
@@ -5,11 +5,11 @@
5
5
  ![pnpm](https://img.shields.io/badge/pnpm-10.x-f69220?logo=pnpm&logoColor=white)
6
6
  ![Vitest](https://img.shields.io/badge/tests-Vitest-6E9F18?logo=vitest&logoColor=white)
7
7
 
8
- **把编码 agent 的 CLI 会话与公开 ChatGPT 分享导出成 Markdown 或单文件 HTML。** `asmgr`(Agent Session ManaGeR)读取 GitHub Copilot CLI、Claude Code、OpenAI Codex CLI、DeepSeek Harness(DSH)写在本地的会话历史,也可捕获公开 ChatGPT `/share/` 页面,再把选定的会话导出成自包含报告;来源无法完整保留的内容会显式标记。它是**一个**无 scope 的公开 npm 包,命令也叫 `asmgr`;HTML 与 Markdown 是它的导出能力,而非独立发布的产品。
8
+ **把编码 agent 的 CLI 会话与公开 ChatGPT 分享导出成 Markdown 或单文件 HTML。** `asmgr`(Agent Session ManaGeR)读取 GitHub Copilot CLI、Claude Code、OpenAI Codex CLI、DeepSeek Harness(DSH)及 Cursor Agent 写在本地的会话历史,也可捕获公开 ChatGPT `/share/` 页面,再把选定的会话导出成自包含报告;来源无法完整保留的内容会显式标记。它是**一个**无 scope 的公开 npm 包,命令也叫 `asmgr`;HTML 与 Markdown 是它的导出能力,而非独立发布的产品。
9
9
 
10
10
  HTML 产物高度复刻 Copilot CLI 内置 `/share html` 的排版(Primer 主题、sticky header、类型筛选 pill、侧栏目录、上一条/下一条用户消息跳转、搜索),差异见 [ADR 0003](docs/adr/0003-archive-reconstruction-fidelity.md)。Markdown 产物遵循 Copilot CLI `/share file` 的结构与约定(`### 💬/👤/🔧/✅` 标题、`<sub>⏱️</sub>` 耗时戳、`<details>` 折叠、diff 围栏、`[!NOTE]` 头块)。
11
11
 
12
- 它对 agent 状态目录**只读**:不写 `.copilot`、`.claude`、`.codex`、`.dsh`。传本地 session id 或 `--file` 时,`list` / `search` / `show` / `html` / `md` 都严格本地。只有显式导入或直接读取 ChatGPT 分享 URL,以及按配置访问 restic 仓库的 `backup` 命令会联网。
12
+ 它对 agent 状态目录**只读**:不写 `.copilot`、`.claude`、`.codex`、`.dsh`、`.cursor`。传本地 session id 或 `--file` 时,`list` / `search` / `show` / `html` / `md` 都严格本地。只有显式导入或直接读取 ChatGPT 分享 URL,以及按配置访问 restic 仓库的 `backup` 命令会联网。
13
13
 
14
14
  > **归档 ≠ 恢复。** 导出的报告是有损、只读、给人看的产物,**不能**反推回可 `--resume` 的原生会话。把会话忠实恢复到"另一台机器能续聊"是一条**规划中**的独立能力(来源 = 备份快照 ∪ 另一台机器),与只读归档严格分层——理念见 [ADR 0001](docs/adr/0001-scope-archive-and-restore.md)。
15
15
 
@@ -17,7 +17,9 @@ HTML 产物高度复刻 Copilot CLI 内置 `/share html` 的排版(Primer 主
17
17
 
18
18
  | 目标 | 命令 |
19
19
  |---|---|
20
- | 列出已知会话 | `asmgr list --agent all` |
20
+ | 列出最近活跃会话 | `asmgr list --agent all --limit 20` |
21
+ | 定位 DSH 当前会话(运行时注入) | `asmgr current` |
22
+ | 按工作目录筛选 / 机器读取 | `asmgr list --agent dsh --cwd "$PWD" --json` |
21
23
  | 搜索本地历史 | `asmgr search "关键词" --agent all` |
22
24
  | 在单个会话内搜索 | `asmgr search "关键词" --session <session-id>` |
23
25
  | 打印一个会话 | `asmgr show <session-id> --agent claude` |
@@ -38,12 +40,22 @@ HTML 产物高度复刻 Copilot CLI 内置 `/share html` 的排版(Primer 主
38
40
  - **Claude Code**:读取 `~/.claude/projects/**/*.jsonl`
39
41
  - **Codex CLI**:读取 `~/.codex/sessions/**/*.jsonl`
40
42
  - **DeepSeek Harness(DSH)**:读取 `${DSH_HOME:-~/.dsh}/sessions/<project>/<session>/session[.vN].jsonl[.zstd]`;用 `--dsh-root <path>` 覆盖会话根目录。目录发现选择每个会话的最高版本文件;`--file` 指向单个文件时读取指定版本。
43
+ - **Cursor Agent**:只读 `~/.cursor/chats/<workspace-hash>/<session-id>/store.db` 及相邻 metadata;`--agent cursor`(别名 `cursor-agent`)、`--cursor-root <path>`,也支持 `--file /path/to/store.db`。只读取当前 root 的可达消息图,不混入孤立旧分支。该闭源存储没有稳定公开协议;未验证的 protobuf 数字、缺失 token 用量和逐消息时间戳不做推断,局部缺失会给出诊断。
41
44
  - **ChatGPT 公共分享**:`asmgr import <url>` 从 `/share/<id>` 页面的 React Router 水合数据读取
42
45
  `linear_conversation`。默认托管目录中的快照会自动进入 `list/search/show/html/md`;
43
46
  也可把 URL 直接传给 `show/html/md`,不落盘使用。
44
47
 
45
48
  每个读命令(`list` / `search` / `show` / `html` / `md`)都接受 `--file <path>`(别名 `--events <path>`),读一个显式的 `*.jsonl` / DSH `*.jsonl.zstd` / `*.chatgpt-share.json` 文件——或一个会被遍历出这些文件的目录——而不是 live agent 主目录。每个文件的 agent 格式自动探测(用 `--agent` 覆盖)。未知 JSON 会明确报错,不再静默显示成空会话。
46
49
 
50
+ ### 统一中间格式与用量口径
51
+
52
+ 所有来源经同一读取入口输出版本化 `SessionDocument`,`show -f json` 中的 `document` 是统一格式,`entries` 是由它派生的兼容显示视图。采用固定 DSH format 4 的事件信封、结构化内容块和计量语义,参考提交 `5badb15009ae1756c3afe0ae0cef1faafc290ccc`,并扩展来源证据、线程关系、上下文与额度观测。不会依赖安装中的 DSH 私有 codec,也不会随 DSH 升级自动改变本项目中间格式。设计与边界见 [ADR 0004](docs/adr/0004-unified-session-format.md)。**这不是可供 DSH resume 的日志,也不保证未知来源字段已完整解释。**
53
+
54
+ - `inputTokens` = **未缓存输入**;`cacheReadTokens` / `cacheWriteTokens` 为独立桶;`reasoningTokens` 是输出的子集。
55
+ - 原始来源计数与转换依据保留;Codex 包含缓存的 `input_tokens` 不直接改名为未缓存输入。无法确认语义的值仅保留原始记录。
56
+ - 精确响应增量按 `response_id` 去重;旧日志只能使用最新累计快照时明确标记口径。上下文观测、父会话继承和账号额度不累计为当前线程用量。
57
+ - 缺值保持未知,JSON 省略 / TSV 空列,不假装成零;不把不完整小计包装成完整总量。正文事件时间是时间点,文件名本地时间和文件 mtime 不是可替代的计量时间。
58
+
47
59
  ### DSH 读取与主干
48
60
 
49
61
  **默认自动使用 DSH home,无需传 `--dsh-root`。** 会话目录优先级为:显式 `--dsh-root` → 环境变量 `DSH_HOME` 下的 `sessions/` → 当前用户的 `~/.dsh/sessions/`。`--dsh-root` 仅用于覆盖会话日志根目录,例如读取备份;它不是 DSH 源码目录,也不是项目工作目录。
@@ -61,7 +73,7 @@ DSH 读取采用**独立的只读转录解析器**,不再把归档恢复成可
61
73
 
62
74
  范围保持有限:不递归提取未知插件事件、注入上下文、失败模型尝试或任意 `meta` 的正文;所有具名非 `user` 来源都保持 model-only,不因 `role: user` 就当成人类输入。只显示最终追加消息,packed/embedded 流片段不会重复变成正文;不把压缩 replacement 当成新对话,不重复拼接 fork 的父会话,也不在 `session/end-seed` 处截断后续历史。只显示已知 compact checkpoint 对应的摘要。图片/文件只显示占位符并提示损失;完整工具仍在 text/HTML/Markdown 中保留。HTML/Markdown 暂无独立的主干导出开关。
63
75
 
64
- **兼容策略不是“版本号超出上限就拒读”。** 新版本 header 仍满足已知 JSONL 信封时,继续读取可识别的消息,并标记尚未验证新版本语义;未知事件、内容块、surface 操作和畸形记录产生局部诊断,不丢弃后续可读消息。`show --format json` 的 `diagnostics` 包含 `formatVersion`、处理/忽略/未知计数、未知类型样本及 `issues`(代码、首个非空记录序号、存储 seq、次数;不包含原始 payload)。诊断样本和类型名称有大小上限,省略会明确标记。缺失/未解释内容通过 `source.lossy` 与具体 `source.warning` 暴露:text、dialogue、HTML、Markdown 都显示警告,search 即使没有命中也在 stderr 报出路径与警告。
76
+ **兼容策略不是“版本号超出上限就拒读”。** 新版本 header 仍满足已知 JSONL 信封时,继续读取可识别的消息,并标记尚未验证新版本语义;未知事件、内容块、surface 操作和畸形记录产生局部诊断,不丢弃后续可读消息。`show --format json` 的 `diagnostics` 包含 `formatVersion`、处理/忽略/未知计数、未知类型样本及 `issues`(代码、首个非空记录序号、存储 seq、次数;不包含原始 payload)。诊断样本和类型名称有大小上限,省略会明确标记。缺失/未解释内容通过 `source.lossy` 与具体 `source.warning` 暴露:text、dialogue、HTML、Markdown 都显示警告。search 即使没有命中也汇总解析/兼容性警告;预期的图片/附件占位符属于 `source.notices`,默认不刷 stderr,`--verbose` 才显示,`--quiet` 可关闭全部检索诊断。
65
77
 
66
78
  这不保证任意未来格式都无需维护:如果压缩算法、信封或实际消息布局发生不兼容变化,仍须扩展读取能力;不把新布局猜成旧布局或声称转录完整。新增无关元数据或 descriptor 版本不要求手动升级 pin。压缩日志需要运行时提供 Zstandard API(Node.js ≥ 22.15);无法解压、无效 session 文件头、文件名/header 版本不符或同一代存在多种编码时仍明确报错。目录发现始终选最高一代,不自动回退到过期前代;`--file` 单文件始终读取指定归档。
67
79
 
@@ -156,13 +168,16 @@ HTML 文件是自包含的:搜索、筛选、可折叠条目、侧栏目录、
156
168
 
157
169
  ### `asmgr list`
158
170
 
159
- 以 tab 分隔的行打印发现的会话:
171
+ 默认按源文件 **mtime 降序**(最近活动优先)打印 TSV:`agent`、`session-id`、`path`、`mtime`(UTC ISO 时间)、`size`(字节,压缩文件为压缩大小)、`cwd`。原前三列保持不变;`--sort id` 恢复按 agent/id 排序。mtime 是文件活动时间,不等同于事件时间,也不能证明会话仍在运行。
160
172
 
161
173
  ```bash
162
- asmgr list --agent all
163
- asmgr list --agent claude --claude-root /path/to/claude/projects
174
+ asmgr list --agent dsh --cwd "$PWD" --limit 20
175
+ asmgr list --agent dsh --cwd "$PWD" --json
176
+ asmgr list --agent claude --claude-root /path/to/claude/projects --sort id
164
177
  ```
165
178
 
179
+ `--cwd` 精确匹配记录的工作目录(规范化相对路径、`~` 和尾部斜杠,不递归包含子目录);没有 cwd 的会话不匹配。发现阶段只采样 metadata,不构建完整 timeline;Claude/Codex/Copilot 从前 50 条记录提取 cwd,DSH 使用权威 header。`--json` 输出 metadata 数组,`--limit 0` 列出零条。分组的 JSON 输出则是包含 `ref`、project 和条目统计的摘要数组。
180
+
166
181
  用 `--by project` 或 `--by agent` 分组(默认平铺)。project 取会话记录 cwd 最近的、含 `.git/` 的祖先目录(仅当该 cwd 在本机存在时才探测文件系统);cwd 存在但找不到 `.git` 祖先、或该路径不在本机时,按记录的 cwd 原样分组;只有完全没有 cwd 的会话才归入 `(unscoped)` 桶:
167
182
 
168
183
  ```bash
@@ -170,7 +185,41 @@ asmgr list --by project # 按仓库聚类会话
170
185
  asmgr list --by agent # 按 copilot / claude / codex / chatgpt 分组
171
186
  ```
172
187
 
173
- 分组模式每组打印一个 `# <组> (<数量>)` 头(组间排序,组内按最后活动时间从新到旧),随后是 `组`、`agent`、`session-id`、`最后活动`、`条目数` 的 tab 分隔行。
188
+ 分组模式每组打印一个 `# <组> (<数量>)` 头(组间排序,组内按所选排序),随后是 `组`、`agent`、`session-id`、`最后事件时间`、`条目数` 的 tab 分隔行。**分组需要完整解析以统计条目**,比默认 metadata 列表重;解析并发也有上限。
189
+
190
+ ### 统计、线程关系与账号额度
191
+
192
+ ```bash
193
+ asmgr list -a codex --stats --sort peak_ctx --limit 20
194
+ asmgr list -a codex --stats -f json | jq '.[].stats'
195
+ asmgr list -a codex --role guardian
196
+ asmgr tree <session-id> -a codex --json
197
+ asmgr quota -a codex --timezone Asia/Shanghai -f json
198
+ asmgr show <session-id> -a codex --no-guardian
199
+ asmgr search "关键词" -a codex --include-guardian
200
+ ```
201
+
202
+ `list --stats` 在原六列之后追加 `peak_ctx`、`ctx_util%`、`in`、`cached`、`out`、`cache%`、`compact`;JSON 使用 `stats.peakContextTokens/peakContextUtilization/billedInputTokens/totals.cacheReadTokens/totals.outputTokens/cacheReadRatio/compactions`。`-f json` 与 `--json` 等价。`peak_ctx` 是 Codex **最后请求的原始 input_tokens 最大观测值**,不是模型窗口上限或累计 total;`ctx_util%` 配对使用该最大样本自己的窗口,缺窗口则未知。`in` 是确切的总 prompt 输入(包括已核实缓存),`cached` 是缓存读取,`cache% = cached/in`。统计排序先计算所选全集再取 limit;默认列表仍只读 metadata。统计排序包括 `peak_ctx/ctx_util/input/cached/output/cache/compact`,未知值排末尾;统计与 `--by` 分组不能组合。`--verbose` 显示坏行、未知记录及计量缺口。show 的 `--role` 同时过滤 JSON 的 entries 与 document 消息事件;此 reduced view 以 `document.view` 标记,并省略可能混合角色的原生 opaque 内容,避免通过第二载体暴露被排除的消息。
203
+
204
+ 列表的 `--role main|subagent|guardian|unknown` 筛**会话身份**,与 show/search 的消息角色不同。`tree` 区分父子与 fork,标明缺失父节点、重复 ID 和循环;时间来自记录,不用 mtime 冒充活动或运行状态。并发数只是记录区间的半开重叠,不代表此刻仍运行。默认最多显示 128 层,可用 `--max-depth 0–256` 调整,截断会明确标记。Codex `show` 默认附上 guardian 子线程并保留其来源;`--no-guardian` 关闭。search 默认跨库排除 guardian 噪音,`--include-guardian` 可恢复;显式 `--session` 或单文件选择会尊重该选择,并先做完整的 ID 歧义检查。
205
+
206
+ `quota` 从统一文档读取 Codex primary/secondary 观测,合并所选会话为按小时的 min/max/last 轨迹,保留原始数值精度、余额字符串和来源。默认 UTC,`--timezone` 接受 IANA 时区;重复的 DST 小时按 UTC offset 区分。水位下降/重置时间变化只标记**观测到的证据**,不宣称全局重置。仅请求时刻有采样,间隙未知;`limit_id` 是额度桶,**不是账号 ID**,缺账号标识时明确提示可能混合不同账号。账号额度不按 cwd 百分比分摊。
207
+
208
+ DSH 的 raw TokenUsage 缺省缓存字段在 harness UI fold 中按 0 折算;本中间层保留缺失为未知,并在每条转换说明中标明此区别,不把显示默认值伪装成原始计量数据。Cursor 未验证的字段也不推断成 token 用量,读取方式与限制见 [Cursor 格式说明](docs/cursor-format.md)。本机全量读取、成品验证、独立审阅与残余边界见 [验证记录](docs/validation-unified-sessions.md)。
209
+
210
+ ### `asmgr current`
211
+
212
+ DSH 已提供运行时 `DSH_SESSION_ID` 时,`asmgr current` 直接打印该 ID;`asmgr current --json` 查询该会话的本地 metadata(支持 `--dsh-root`)。变量未设置会明确报错,**不会把最新 mtime 冒充当前会话**。
213
+
214
+ 定位和复盘优先缩小范围,再搜索:
215
+
216
+ ```bash
217
+ id=$(asmgr current) # 必须在 DSH 的命令执行环境内
218
+ asmgr search "关键词" --agent dsh --session "$id" --role user
219
+ asmgr show "$id" --agent dsh -f dialogue --role user
220
+ # 没有运行时身份时,先按 cwd 查看最近会话,再核对目标 ID
221
+ asmgr list --agent dsh --cwd "$PWD" --limit 5
222
+ ```
174
223
 
175
224
  ### `asmgr search`
176
225
 
@@ -183,9 +232,21 @@ asmgr search "database migration" --session <session-id> # 只在一个会话
183
232
 
184
233
  每条命中是一行 tab 分隔、以 `project` 列(cwd 最近的含 `.git` 祖先目录;找不到 `.git` 祖先时为 cwd 原值,无 cwd 时为 `(unscoped)`)开头:`project`、`agent`、`session-id`、`#条目`、`role/kind`、`摘录`。
185
234
 
186
- `--session <id>` 把搜索限定到一个会话(先精确匹配 id,否则按前缀匹配;DSH 的 id 是 `session-<uuid>`,直接给裸 uuid 也可以)——用来在**当前这个会话**里按关键词找模型回复,不必先用 `--file` 指路径。
235
+ `--session <id>` 把搜索限定到一个会话(先精确匹配 id,否则按前缀匹配;DSH 的 id 是 `session-<uuid>`,直接给裸 uuid 也可以)。前缀或重复 ID 有歧义时拒绝,要求更长 ID 或 `--agent`/`--file` 缩小范围,不再随意选第一个。
236
+
237
+ - 默认按会话源文件 mtime 降序检索,**同一会话内保持原 timeline 顺序**。达到 `-l/--limit` 即停止安排下一批;`--concurrency`(别名 `-j`,默认 2,范围 1–32)限制 worker 并发和预读,最多多读一批中的其余会话。`-j 1` 完全串行、无会话预读。worker 不可用时回退到同一规范读取器,不把运行时能力缺失误报成损坏会话;`--verbose` 显示实际 backend。并行度过大会增加内存,不保证越大越快。
238
+ - `--no-early-exit` 扫描整个工作集以检查诊断,但仍只输出 limit 条;`-l 0` 不发现/读取会话。关键词为空、非整数或负 limit 明确报错。**命中总数不足 limit 时仍必须全扫**,这不代表提前终止失效。
239
+ - `--cwd <path>` 与 list 的过滤语义相同;`--role user|assistant|tool|reasoning|system|event` 只搜指定规范化角色。
240
+ - 只搜索可见的规范转录:不对原始 JSON 做全文搜索,因此不会误命中注入上下文、失败尝试或未知插件 payload。压缩读取采用严格增量帧扫描,不为搜索/list 整文件解压,不依赖本机 DSH。
241
+ - 无法读取的会话不阻止其他会话命中;stderr 汇总次数并保留少量路径样本,解析/兼容性警告按同类去重。附件占位符默认静默;`--verbose` 查看逐条详情与附件说明,`-q/--quiet` 关闭全部检索诊断。完整导出的保真度警告仍保留。
242
+
243
+ #### 派生缓存与隐私
187
244
 
188
- 跨会话搜索对每个会话独立解析:遇到官方迁移器拒绝或损坏的存档时,在 stderr 逐条报出路径与原因后跳过,不中断其余会话的检索;stdout 的命中行不受影响。
245
+ search 默认缓存**规范转录的可搜索文本索引**(包括工具文本与诊断,不是原始日志或完整 timeline),避免每次全库查询都重新解压与重建 timeline。热查询先用已校验的 UTF16 三字符 Bloom 摘要保守排除不含关键词的会话(允许误报,不漏报);不足 3 个 UTF16 单元的短关键词绕过 Bloom,再用已校验的文本索引字节预筛。可能命中时回读规范源,确保工具详情、摘录和原 index 不改变。缓存由源路径、agent/id 与文件 stat(mtime、size、ctime、inode)校验;源变化自动失效,读取过程中变化的源不写缓存。一个会话只占一个可替换槽位,不保留每次修改的旧版本。缓存格式/解析语义有独立版本;坏缓存、只读缓存目录或写入失败会回退原始解析,不影响命中。
246
+
247
+ 路径优先级:`--cache-dir <path>` → `ASMGR_CACHE_HOME` → `${XDG_CACHE_HOME:-~/.cache}/asmgr`;实际文件在 `search/search-text-2/`。每个逻辑槽位包含 gzip 文本索引与小型 `.meta.json` 摘要;目录为 `0700`,文件为 `0600`。**gzip 不是加密**,缓存可能含私密对话和工具输出,应和会话历史一样保护,并从云同步/公开备份中排除。单个快照超过 128 MiB 时不缓存。`--no-cache` 完全绕开缓存的读写,也适合完整原始读取验收;缓存可删除并随下一次查询重建,但删除缓存不等于删除原始会话。Copilot 实时 SQLite/db-turns 不使用持久负索引:WAL 里的新消息可能不改变主 DB 的 stat,不能据此跳过检索。
248
+
249
+ 冷首次全库查询仍须处理所有候选历史(不足 limit 时无法免除),后续关键词共享缓存;没有后台索引服务,不触碰原生历史目录。库 API 的 `searchRefs` 不默认写缓存,只有调用方显式传 `cacheDir` 才使用。
189
250
 
190
251
  ### `asmgr import`
191
252
 
@@ -241,6 +302,25 @@ asmgr show 'https://chatgpt.com/share/<id>' --format dialogue
241
302
 
242
303
  `--format dialogue` 只保留**用户消息 / 交互式提问与选项 / 用户决策或回答 / 压缩摘要 / 助手回复**,跳过普通工具调用的全部内容与 reasoning。DSH 的 `ask_user_question` 保留题目、全部选项、单/多选信息、选中项和自由回答;Copilot 的 `ask_user` 保留题目、全部候选项及回答。工具噪音被剔掉后,每条用户 prompt 直接紧跟回答它的助手回复,prompt↔回复的对应关系一目了然——适合会话复盘、交接和收尾盘点等需要通读对话主干的场景。`--format text` 则含完整工具参数+结果、子代理/技能/计划/压缩统计。
243
304
 
305
+ #### dialogue 头部与角色过滤
306
+
307
+ `show -f dialogue` 每个条目的头部为 `## N. role/kind 时间戳`:`N` 是完整 timeline 中从 1 开始的原始位置,过滤后不会重编号;时间戳若来源没有记录则省略。dialogue 不把自由文本标题插进头部;text 格式可能包含标题。文件开头还有 session/agent/cwd/started/warning metadata。
308
+
309
+ ```text
310
+ ## 3. user/message 2026-10-04T17:00:00.000Z
311
+
312
+ 用户原话
313
+ ```
314
+
315
+ 无需用正则猜头部提取用户发言:
316
+
317
+ ```bash
318
+ asmgr show <id> --agent dsh -f dialogue --role user
319
+ asmgr show <id> --agent dsh -f json --role user # 机器处理建议 JSON
320
+ ```
321
+
322
+ `--role` 同样适用于 text/JSON,保留原 index;dialogue 的角色过滤仍与主干过滤取交集。
323
+
244
324
  ### `asmgr html`
245
325
 
246
326
  写出一份自包含 HTML 报告,支持搜索、筛选、侧栏目录、主题切换、Markdown 表格与 KaTeX 数学: