asmgr 0.1.0 → 0.2.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.
- package/README.md +174 -146
- package/dist/asmgr.mjs +1277 -119
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|

|
|
6
6
|

|
|
7
7
|
|
|
8
|
-
**把编码 agent 的 CLI
|
|
8
|
+
**把编码 agent 的 CLI 会话与公开 ChatGPT 分享导出成 Markdown 或单文件 HTML。** `asmgr`(Agent Session ManaGeR)读取 GitHub Copilot CLI、Claude Code、OpenAI Codex CLI 写在本地的会话历史,也可捕获公开 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
|
|
12
|
+
它对 agent 状态目录**只读**:不写 `.copilot`、`.claude`、`.codex`。传本地 session id 或 `--file` 时,`list` / `search` / `show` / `html` / `md` 都严格本地。只有显式导入或直接读取 ChatGPT 分享 URL,以及按配置访问 restic 仓库的 `backup` 命令会联网。
|
|
13
13
|
|
|
14
|
-
> **归档 ≠ 恢复。** 导出的报告是有损、只读、给人看的产物,**不能**反推回可 `--resume` 的原生会话。把会话忠实恢复到"另一台机器能续聊"是一条**规划中**的独立能力(来源 = 备份快照 ∪ 另一台机器),与只读归档严格分层——理念见 [ADR 0001](docs/adr/0001-scope-archive-and-restore.md)
|
|
14
|
+
> **归档 ≠ 恢复。** 导出的报告是有损、只读、给人看的产物,**不能**反推回可 `--resume` 的原生会话。把会话忠实恢复到"另一台机器能续聊"是一条**规划中**的独立能力(来源 = 备份快照 ∪ 另一台机器),与只读归档严格分层——理念见 [ADR 0001](docs/adr/0001-scope-archive-and-restore.md)。
|
|
15
15
|
|
|
16
16
|
## 功能
|
|
17
17
|
|
|
@@ -22,32 +22,48 @@ HTML 产物高度复刻 Copilot CLI 内置 `/share html` 的排版(Primer 主
|
|
|
22
22
|
| 在单个会话内搜索 | `asmgr search "关键词" --session <session-id>` |
|
|
23
23
|
| 打印一个会话 | `asmgr show <session-id> --agent claude` |
|
|
24
24
|
| 只看对话主干(跳过工具调用) | `asmgr show <session-id> --format dialogue` |
|
|
25
|
+
| 导入公开 ChatGPT 分享 | `asmgr import 'https://chatgpt.com/share/<id>'` |
|
|
26
|
+
| 直接读取 ChatGPT 分享主干 | `asmgr show 'https://chatgpt.com/share/<id>' --format dialogue` |
|
|
25
27
|
| 导出 Markdown(Copilot `/share file` 风格) | `asmgr md <session-id> -o session.md` |
|
|
26
28
|
| 导出 HTML(高度复刻 `/share html`) | `asmgr html <session-id> -o session.html` |
|
|
29
|
+
| 直接把 ChatGPT 分享导出 HTML | `asmgr html 'https://chatgpt.com/share/<id>' -o session.html` |
|
|
27
30
|
| 读取任意位置的会话文件(scp 来的 / 恢复出来的) | `asmgr html --file /path/to/events.jsonl -o session.html` |
|
|
28
|
-
|
|
|
29
|
-
|
|
|
31
|
+
| 搜索任意位置的会话目录 | `asmgr search "关键词" --file /path/to/sessions` |
|
|
32
|
+
| 运行加密增量备份 | `asmgr backup run --dry-run` |
|
|
33
|
+
| 把备份快照恢复到隔离缓存 | `asmgr backup cache latest --target ~/.cache/asmgr/restic-cache` |
|
|
30
34
|
|
|
31
35
|
## 支持的 agent 与数据来源
|
|
32
36
|
|
|
33
37
|
- **Copilot CLI**:读取 `~/.copilot/session-state/*/events.jsonl`;同时用 `~/.copilot/session-store.db` 列出会话与元信息。events.jsonl 缺失(老会话被 prune、或只迁移了 DB)时回退到 DB 的 `turns` 表(lossy:只有 user/assistant 文本,工具与用户决策不可恢复)。所有读命令可用 `--copilot-db <path>` 覆盖 DB 路径。
|
|
34
38
|
- **Claude Code**:读取 `~/.claude/projects/**/*.jsonl`
|
|
35
39
|
- **Codex CLI**:读取 `~/.codex/sessions/**/*.jsonl`
|
|
40
|
+
- **ChatGPT 公共分享**:`asmgr import <url>` 从 `/share/<id>` 页面的 React Router 水合数据读取
|
|
41
|
+
`linear_conversation`。默认托管目录中的快照会自动进入 `list/search/show/html/md`;
|
|
42
|
+
也可把 URL 直接传给 `show/html/md`,不落盘使用。
|
|
36
43
|
|
|
37
|
-
每个读命令(`list` / `search` / `show` / `html` / `md`)都接受 `--file <path>`(别名 `--events <path>`),读一个显式的 `*.jsonl` 文件——或一个会被遍历出这些文件的目录——而不是 live agent 主目录。每个文件的 agent 格式自动探测(用 `--agent`
|
|
44
|
+
每个读命令(`list` / `search` / `show` / `html` / `md`)都接受 `--file <path>`(别名 `--events <path>`),读一个显式的 `*.jsonl` / `*.chatgpt-share.json` 文件——或一个会被遍历出这些文件的目录——而不是 live agent 主目录。每个文件的 agent 格式自动探测(用 `--agent` 覆盖)。未知 JSON 会明确报错,不再静默显示成空会话。
|
|
38
45
|
|
|
39
46
|
## <a id="install"></a>安装
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
`asmgr` 已发布为单一、无 scope 的公开 npm 包:
|
|
42
49
|
|
|
43
|
-
### npm
|
|
50
|
+
### npm
|
|
44
51
|
|
|
45
52
|
```bash
|
|
46
53
|
npm i -g asmgr
|
|
47
54
|
asmgr list --agent all
|
|
48
55
|
```
|
|
49
56
|
|
|
50
|
-
|
|
57
|
+
各安装方式当前能力如下:
|
|
58
|
+
|
|
59
|
+
| 安装方式 | 读取、搜索、导入与导出 | `asmgr backup` |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| npm / `npm i -g github:` | ✅ | ❌ 暂未包含备份运行时 |
|
|
62
|
+
| 原生二进制 | ✅,但不读取 Copilot live SQLite | ❌ 暂未包含备份运行时 |
|
|
63
|
+
| 源码 checkout | ✅ | ✅ |
|
|
64
|
+
|
|
65
|
+
<details>
|
|
66
|
+
<summary>其他安装方式与运行时差异</summary>
|
|
51
67
|
|
|
52
68
|
### 原生二进制(无需 Node)
|
|
53
69
|
|
|
@@ -92,6 +108,8 @@ asmgr list --agent all
|
|
|
92
108
|
|
|
93
109
|
开发时直接跑源码:`pnpm dev list --agent all`(经 tsx)。自行编译原生二进制(需要 [Bun](https://bun.sh)):`pnpm run binaries`,四平台产物落在 `dist/asmgr-*`。
|
|
94
110
|
|
|
111
|
+
</details>
|
|
112
|
+
|
|
95
113
|
## 首次运行
|
|
96
114
|
|
|
97
115
|
1. 按上面任一方式装好 `asmgr`。
|
|
@@ -127,7 +145,7 @@ asmgr list --agent claude --claude-root /path/to/claude/projects
|
|
|
127
145
|
|
|
128
146
|
```bash
|
|
129
147
|
asmgr list --by project # 按仓库聚类会话
|
|
130
|
-
asmgr list --by agent # 按 copilot / claude / codex 分组
|
|
148
|
+
asmgr list --by agent # 按 copilot / claude / codex / chatgpt 分组
|
|
131
149
|
```
|
|
132
150
|
|
|
133
151
|
分组模式每组打印一个 `# <组> (<数量>)` 头(组间排序,组内按最后活动时间从新到旧),随后是 `组`、`agent`、`session-id`、`最后活动`、`条目数` 的 tab 分隔行。
|
|
@@ -145,6 +163,47 @@ asmgr search "database migration" --session <session-id> # 只在一个会话
|
|
|
145
163
|
|
|
146
164
|
`--session <id>` 把搜索限定到一个会话(先精确匹配 id,否则按前缀匹配)——用来在**当前这个会话**里按关键词找模型回复,不必先用 `--file` 指路径。
|
|
147
165
|
|
|
166
|
+
### `asmgr import`
|
|
167
|
+
|
|
168
|
+
导入公开 ChatGPT 分享页:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
asmgr import 'https://chatgpt.com/share/<conversation-id>'
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
默认写入 asmgr 托管目录,随后可直接用 session id 执行 `list/search/show/html/md`。
|
|
175
|
+
也可以把分享 URL 直接传给 `show/html/md`,跳过本地保存。
|
|
176
|
+
|
|
177
|
+
<details>
|
|
178
|
+
<summary>ChatGPT 存储路径、输出方式与保真限制</summary>
|
|
179
|
+
|
|
180
|
+
托管目录优先使用 `ASMGR_DATA_HOME`,其次使用 `XDG_DATA_HOME`;都未设置时按平台选择:
|
|
181
|
+
|
|
182
|
+
| 平台 | 默认目录 |
|
|
183
|
+
|---|---|
|
|
184
|
+
| Linux | `~/.local/share/asmgr/imports/chatgpt` |
|
|
185
|
+
| macOS | `~/Library/Application Support/asmgr/imports/chatgpt` |
|
|
186
|
+
| Windows | `%LOCALAPPDATA%\asmgr\imports\chatgpt` |
|
|
187
|
+
|
|
188
|
+
三种写入方式的后续读取不同:
|
|
189
|
+
|
|
190
|
+
| 导入方式 | 后续读取 |
|
|
191
|
+
|---|---|
|
|
192
|
+
| 默认目录 | 自动进入 `list/search/show/html/md` |
|
|
193
|
+
| `--chatgpt-root <dir>` | 后续读命令继续传相同的 `--chatgpt-root` |
|
|
194
|
+
| `-o <path>` | 用 `--file <path>` 显式读取;若改为扫描目录,文件名需以 `.chatgpt-share.json` 结尾 |
|
|
195
|
+
|
|
196
|
+
新快照权限为 `0600`;目标已存在时拒绝覆盖,确认要刷新才加 `--force`。普通 ChatGPT 页面、私有
|
|
197
|
+
`/c/...`、`/g/.../c/...` 地址栏会话及其它网站 URL 都不会发起抓取:检测到地址栏私有
|
|
198
|
+
会话链接时,会用中文明确提示先在 ChatGPT 中点击“分享”,再复制 `/share/` 链接。
|
|
199
|
+
|
|
200
|
+
捕获不启动浏览器:直接解码页面 HTML 内的 turbo-stream 水合数据。快照保留完整公开
|
|
201
|
+
`linear_conversation`,便于未来适配器改进后重新解析。公开页隐藏的工具结果无法恢复;
|
|
202
|
+
图片或附件若只有资源指针而没有内容,会显示占位符并把来源标记为 lossy。工具调用与结果
|
|
203
|
+
只有在同一用户轮次内存在唯一匹配时才合并,关联不明确时保留独立结果或 pending 状态。
|
|
204
|
+
|
|
205
|
+
</details>
|
|
206
|
+
|
|
148
207
|
### `asmgr show`
|
|
149
208
|
|
|
150
209
|
以 text、dialogue 或 JSON 打印一个会话:
|
|
@@ -153,20 +212,30 @@ asmgr search "database migration" --session <session-id> # 只在一个会话
|
|
|
153
212
|
asmgr show <session-id> --agent codex
|
|
154
213
|
asmgr show <session-id> --agent copilot --format dialogue
|
|
155
214
|
asmgr show <session-id> --agent codex --format json
|
|
215
|
+
asmgr show 'https://chatgpt.com/share/<id>' --format dialogue
|
|
156
216
|
```
|
|
157
217
|
|
|
158
218
|
`--format dialogue` 只保留**用户消息 / 用户决策(`ask_user` 的回答)/ 压缩摘要 / 助手回复**,跳过工具调用与 reasoning。工具噪音被剔掉后,每条用户 prompt 直接紧跟回答它的助手回复,prompt↔回复的对应关系一目了然——适合会话复盘、交接和收尾盘点等需要通读对话主干的场景。`--format text` 则含完整工具参数+结果、子代理/技能/计划/压缩统计。
|
|
159
219
|
|
|
160
220
|
### `asmgr html`
|
|
161
221
|
|
|
162
|
-
写出一份自包含 HTML
|
|
222
|
+
写出一份自包含 HTML 报告,支持搜索、筛选、侧栏目录、主题切换、Markdown 表格与 KaTeX 数学:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
asmgr html <session-id> --agent copilot -o report.html
|
|
226
|
+
asmgr html <session-id> -s agent-summary.html -o report.html # 顶部钉一份 HTML 总结
|
|
227
|
+
asmgr html 'https://chatgpt.com/share/<id>' -o report.html
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
<details>
|
|
231
|
+
<summary>HTML 与 Copilot CLI `/share html` 的差异</summary>
|
|
163
232
|
|
|
164
233
|
- **用 React 渲染,而非官方 vanilla bundle 资产。** 抽取的上游 CSS/JS 只当逆向参照,不随运行时产物发布。
|
|
165
234
|
- **Shiki 语法高亮**,覆盖 markdown 代码围栏与 diff 风格的工具输出,双 light+dark 主题,页面切主题时代码无需重载即重新着色。
|
|
166
235
|
- **24 小时制时间戳**(会话起点 `YYYY-MM-DD HH:MM:SS`;同日条目 `HH:MM:SS`,跨日 `MM-DD HH:MM:SS`)——en-US 默认的 12 小时制(`PM/AM`)太容易读错。
|
|
167
236
|
- **耗时 pill**,由 `startedAt` → 最后一条条目算出,显示在 header。
|
|
168
237
|
- **agent 总结卡片**,用 `--summary <file.html>` 钉在时间线顶部(原样渲染受信任 HTML;`data-index="summary"`,真实第 1 条仍是第 1 条)。
|
|
169
|
-
-
|
|
238
|
+
- **合并的工具卡片**,六种结果态(success / failure / rejected / denied / pending / redacted),配对应的边框色与状态图标。
|
|
170
239
|
- **`ask_user` 的回答被抽成一等「用户决策」条目**(`user/decision`):既保留原始工具卡片,又让用户的选择/回答在时间线里单独、显眼地出现——复盘或交接时不会把决策埋没在成百上千次工具调用里。
|
|
171
240
|
- **子代理 / 技能 / 计划条目**,从 `events.jsonl` 解析、各自成卡片 + 筛选 pill。子代理卡片在可得时显示记录到的身份、模型、描述、失败详情。这些超出 Copilot 自身 `/share html` 的筛选集。
|
|
172
241
|
- **数据源回退警告 pill**,当解析器不得不读 `events.jsonl` 之外的东西时显示在 header;回退到 `db.turns` 时进一步说明「交互式用户决策与工具条目在此模式下不可恢复」。
|
|
@@ -174,10 +243,7 @@ asmgr show <session-id> --agent codex --format json
|
|
|
174
243
|
- **单行 info 条目**(模型切换 / 取消)默认展开而非折叠——与官方 bundle 不同,让「Model changed from X to Y」「Operation cancelled by user」这类一行信息一眼可见;多行 info 仍折叠。
|
|
175
244
|
- **只存在于 live 内存的条目离线无法重建**,包括吉祥物启动横幅、临时重试提示、`/share` 成功回执。见 [ADR 0003](docs/adr/0003-archive-reconstruction-fidelity.md) 与下文[「Copilot 时间线与离线映射」](#timeline-ref)。
|
|
176
245
|
|
|
177
|
-
|
|
178
|
-
asmgr html <session-id> --agent copilot -o report.html
|
|
179
|
-
asmgr html <session-id> -s agent-summary.html -o report.html # 顶部钉一份 HTML 总结
|
|
180
|
-
```
|
|
246
|
+
</details>
|
|
181
247
|
|
|
182
248
|
### `asmgr md`
|
|
183
249
|
|
|
@@ -187,41 +253,93 @@ asmgr html <session-id> -s agent-summary.html -o report.html # 顶部钉一份
|
|
|
187
253
|
asmgr md <session-id> --agent copilot -o report.md
|
|
188
254
|
asmgr md <session-id> --no-reasoning -o report.md # 去掉 reasoning 条目
|
|
189
255
|
asmgr md <session-id> -s summary.md -o report.md # 注入一份 markdown 总结
|
|
256
|
+
asmgr md 'https://chatgpt.com/share/<id>' -o report.md
|
|
190
257
|
```
|
|
191
258
|
|
|
192
259
|
### `asmgr backup`
|
|
193
260
|
|
|
194
|
-
`backup`
|
|
261
|
+
`backup` 是正式的 restic 备份命令组:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
asmgr backup run --dry-run
|
|
265
|
+
asmgr backup run
|
|
266
|
+
asmgr backup cache latest --target ~/.cache/asmgr/restic-cache
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
`backup run` 默认备份 `~/.copilot`、`~/.claude`、`~/.codex` 与 asmgr 托管的 ChatGPT
|
|
270
|
+
导入目录,只处理实际存在的路径。运行时会先尽力把 Copilot 的 SQLite WAL 合入主库,
|
|
271
|
+
再执行加密、去重、增量备份;SQLite 热文件、锁文件和 Copilot 进程日志不会进入快照。
|
|
272
|
+
每次快照带 `agent-session-manager` 与当前主机标签,并应用 daily / weekly / monthly
|
|
273
|
+
保留策略。
|
|
274
|
+
|
|
275
|
+
`backup cache` 把指定快照恢复到独立缓存,明确拒绝 home 目录及 live 的
|
|
276
|
+
`~/.copilot`、`~/.claude`、`~/.codex`,也拒绝 asmgr 托管的 ChatGPT 导入目录。
|
|
277
|
+
缓存用于 `list/search/show/html/md --file`,不等于把会话恢复成原 agent 可以
|
|
278
|
+
`--resume` 的状态。
|
|
279
|
+
|
|
280
|
+
> 当前备份命令需要从源码 checkout 运行;npm 包和原生二进制尚未包含备份运行时。
|
|
281
|
+
|
|
282
|
+
<details>
|
|
283
|
+
<summary>备份配置与 systemd 自动运行</summary>
|
|
284
|
+
|
|
285
|
+
#### 配置
|
|
286
|
+
|
|
287
|
+
复制配置模板并限制权限:
|
|
195
288
|
|
|
196
289
|
```bash
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
asmgr backup # `backup run` 的向后兼容别名
|
|
200
|
-
asmgr backup cache latest --target ~/.cache/asmgr/restic-cache # 把一个快照恢复进缓存目录
|
|
290
|
+
cp secrets.env.example secrets.env
|
|
291
|
+
chmod 600 secrets.env
|
|
201
292
|
```
|
|
202
293
|
|
|
203
|
-
|
|
294
|
+
必填项是 `RESTIC_REPOSITORY` 与 `RESTIC_PASSWORD`;S3 兼容后端还需要
|
|
295
|
+
`AWS_ACCESS_KEY_ID` 和 `AWS_SECRET_ACCESS_KEY`。可用 `RESTIC_BIN` 覆盖 restic
|
|
296
|
+
位置、用 `BACKUP_AGENT_DIRS` 调整数据源、用 `BACKUP_EXCLUDE_REWIND=1` 排除
|
|
297
|
+
Copilot rewind 快照。通过 `--chatgpt-root` 或 `-o` 放到其它位置的 ChatGPT 快照不会
|
|
298
|
+
自动进入备份,需要显式加入 `BACKUP_AGENT_DIRS`。
|
|
204
299
|
|
|
205
|
-
|
|
300
|
+
新仓库先加载配置并初始化,再运行备份:
|
|
206
301
|
|
|
207
302
|
```bash
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
asmgr
|
|
303
|
+
set -a; source secrets.env; set +a
|
|
304
|
+
restic init
|
|
305
|
+
asmgr backup run --dry-run
|
|
306
|
+
asmgr backup run
|
|
211
307
|
```
|
|
212
308
|
|
|
309
|
+
`RESTIC_PASSWORD` 是读取所有快照的唯一密钥,初始化后必须保存到密码管理器或另一台设备。
|
|
310
|
+
|
|
311
|
+
#### 自动运行
|
|
312
|
+
|
|
313
|
+
`systemd/` 提供 user service 与 timer 示例,每天运行一次,并用随机延迟避免整点拥塞;
|
|
314
|
+
`Persistent=true` 会在机器重新启动后补跑错过的任务。复制示例后按源码 checkout 和日志
|
|
315
|
+
位置调整 service,再启用 timer:
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
mkdir -p ~/.config/systemd/user
|
|
319
|
+
cp systemd/agent-session-manager.service.example ~/.config/systemd/user/agent-session-manager.service
|
|
320
|
+
cp systemd/agent-session-manager.timer.example ~/.config/systemd/user/agent-session-manager.timer
|
|
321
|
+
systemctl --user daemon-reload
|
|
322
|
+
systemctl --user enable --now agent-session-manager.timer
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
同一个 restic 仓库只应由一台机器负责定时运行。需要在登出后继续执行时,为该用户启用
|
|
326
|
+
systemd lingering。
|
|
327
|
+
|
|
328
|
+
</details>
|
|
329
|
+
|
|
213
330
|
## 从 live 目录之外读取会话
|
|
214
331
|
|
|
215
|
-
`--file <path>`(别名 `--events <path>`)让 `list` / `search` / `show` / `html` / `md` 读一个显式路径,而不是
|
|
332
|
+
`--file <path>`(别名 `--events <path>`)让 `list` / `search` / `show` / `html` / `md` 读一个显式路径,而不是 live agent / import 主目录:
|
|
216
333
|
|
|
217
334
|
```bash
|
|
218
335
|
# 从别的机器拷来的单个会话文件(agent 自动探测)
|
|
219
336
|
asmgr show --file ~/dl/events.jsonl --format json
|
|
220
337
|
asmgr html --file ~/dl/events.jsonl -o report.html
|
|
338
|
+
asmgr show --file ~/dl/conversation.chatgpt-share.json --format dialogue
|
|
221
339
|
|
|
222
|
-
# 整个目录(遍历 *.jsonl;每个文件各自探测 agent)
|
|
223
|
-
asmgr list --file /tmp/
|
|
224
|
-
asmgr search "migration" --file /tmp/
|
|
340
|
+
# 整个目录(遍历 *.jsonl / *.chatgpt-share.json;每个文件各自探测 agent)
|
|
341
|
+
asmgr list --file /tmp/session-archive
|
|
342
|
+
asmgr search "migration" --file /tmp/session-archive
|
|
225
343
|
```
|
|
226
344
|
|
|
227
345
|
`--file` 指向单个文件时,`<session-id>` 参数可省。指向的目录若产出多个会话,传一个 `<session-id>` 挑一个(用 `asmgr list --file <dir>` 看 id)。
|
|
@@ -229,21 +347,23 @@ asmgr search "migration" --file /tmp/restored-cache
|
|
|
229
347
|
## 术语
|
|
230
348
|
|
|
231
349
|
- **会话(Session)**:agent CLI 持久化的一次对话,可由 UUID、JSONL 路径,或某 agent 本地数据库中的一行标识。
|
|
232
|
-
- **agent 适配器(Adapter)**:知道如何发现并解析某一家 agent 持久化格式的代码。当前适配 GitHub Copilot CLI、Claude Code、OpenAI Codex CLI
|
|
350
|
+
- **agent 适配器(Adapter)**:知道如何发现并解析某一家 agent 持久化格式的代码。当前适配 GitHub Copilot CLI、Claude Code、OpenAI Codex CLI 与 ChatGPT 公共分享快照。
|
|
233
351
|
- **事件(Event)**:agent 持久化流里的一条原始记录。Copilot 的事件存在 `events.jsonl`,是离线时间线重建的输入,而非 live `/share html` 直接渲染的对象。
|
|
234
352
|
- **时间线条目(Timeline entry)**:时间线里的一个展示单元(用户消息、助手回复、reasoning 块、工具调用等)。Copilot 把 live 条目放内存里;`asmgr` 从持久化事件重建规范化条目,供搜索与渲染共用。
|
|
235
353
|
- **归档(Archive / 只读检索)**:`asmgr` 只读地取回历史会话——搜索、文本显示、JSON 导出、给人看的 HTML/Markdown。归档**从不**把会话恢复回原 agent 的 live 状态。
|
|
236
354
|
- **恢复(Restore)**:忠实重建**可 `--resume` 的原生会话状态**(规划中)。**归档 ≠ 恢复**:报告不可反推回可续聊的原生态。
|
|
237
|
-
- **归档源(Archive source)**:可读取会话文件的地方——包括 live 本地 agent
|
|
355
|
+
- **归档源(Archive source)**:可读取会话文件的地方——包括 live 本地 agent 目录,以及通过 `--file` 显式指定的文件或目录。
|
|
238
356
|
|
|
239
357
|
## 设计文档(ADR)
|
|
240
358
|
|
|
241
359
|
重要决策的理念记录在 [`docs/adr/`](docs/adr/):
|
|
242
360
|
|
|
243
|
-
- [ADR 0001](docs/adr/0001-scope-archive-and-restore.md) ——
|
|
244
|
-
- [ADR 0002](docs/adr/0002-single-package-asmgr-distribution.md) —— 单一 `asmgr`
|
|
245
|
-
- [ADR 0003](docs/adr/0003-archive-reconstruction-fidelity.md) ——
|
|
246
|
-
|
|
361
|
+
- [ADR 0001](docs/adr/0001-scope-archive-and-restore.md) —— 产品范围与"归档 ≠ 恢复"。
|
|
362
|
+
- [ADR 0002](docs/adr/0002-single-package-asmgr-distribution.md) —— 单一 `asmgr` 包与统一命令入口。
|
|
363
|
+
- [ADR 0003](docs/adr/0003-archive-reconstruction-fidelity.md) —— 归档数据的规范化与保真度。
|
|
364
|
+
|
|
365
|
+
<details>
|
|
366
|
+
<summary>实现参考:Copilot 时间线、目录结构与漂移探针</summary>
|
|
247
367
|
|
|
248
368
|
## <a id="timeline-ref"></a>Copilot 时间线与离线映射(参考)
|
|
249
369
|
|
|
@@ -266,110 +386,6 @@ asmgr search "migration" --file /tmp/restored-cache
|
|
|
266
386
|
|
|
267
387
|
**置信度**:`getTimelineEntries()` 用法、空会话消息、12 类筛选、`reasoningText` 不对称、上列 live-only 条目——置信度高;compaction 时的文件截断机制置信度较低,需对新版本复验。Copilot 升级后重跑[漂移探针](#drift-oracle)并查 unknown 诊断。
|
|
268
388
|
|
|
269
|
-
## 备份配置
|
|
270
|
-
|
|
271
|
-
`asmgr backup`(`backup.sh` 的薄封装)用 [restic](https://restic.net) 对 agent 历史做加密、去重、增量备份。部署相关的值(restic 仓库 URL、凭据、到存储后端的确切网络路径)都放在 `secrets.env`(gitignore、`600`)——不进被跟踪的文件,让仓库里没有内网 IP / 主机名(见下文[「公开前的安全检查」](#safety))。
|
|
272
|
-
|
|
273
|
-
### 备份什么
|
|
274
|
-
|
|
275
|
-
`backup.sh` 读 `BACKUP_AGENT_DIRS`(默认 `~/.copilot:~/.claude:~/.codex`),备份其中存在的 agent 主目录。以 Copilot(`~/.copilot`)为例:
|
|
276
|
-
|
|
277
|
-
| 路径 | 典型大小 | 是什么 | 是否备份 |
|
|
278
|
-
|---|---|---|---|
|
|
279
|
-
| `session-state/<id>/events.jsonl` | 大(合计 GB 级) | 持久化的每会话事件流——resume 时回放、并被 `asmgr` 映射成离线条目 | ✅ 核心 |
|
|
280
|
-
| `session-state/<id>/{checkpoints,files,research}/` | 中小 | 每会话产物(检查点、附件、research 笔记) | ✅ |
|
|
281
|
-
| `session-store.db` | 数十 MB | 全会话的 SQLite 索引(摘要、turns、文件 / 引用索引、FTS) | ✅ —— 先 checkpoint WAL 保证副本自洽 |
|
|
282
|
-
| `session-store.db-wal` / `-shm` | 小 | SQLite WAL / 共享内存(热文件) | ❌ 排除(`exclude.txt`) |
|
|
283
|
-
| `*.lock`(如 `inuse.<pid>.lock`) | 极小 | 运行时锁文件 | ❌ 排除(`exclude.txt`) |
|
|
284
|
-
| `logs/` | 很大(GB 级) | CLI 进程日志 | ❌ 始终排除(`backup.sh` 里)——量大、恢复价值低 |
|
|
285
|
-
| `session-state/<id>/rewind-snapshots/` | 大(GB 级) | 支撑 `/rewind` 撤销功能的快照 | ⚠️ 可选——`BACKUP_EXCLUDE_REWIND=1` 时排除 |
|
|
286
|
-
| `config.json`、`settings.json`、`mcp-config.json`、`servers/` | 极小 | CLI + MCP 配置 | ✅ |
|
|
287
|
-
|
|
288
|
-
Claude Code(`~/.claude`)与 Codex(`~/.codex`)主目录存在时整体备份。
|
|
289
|
-
|
|
290
|
-
**`rewind-snapshots/` 为什么可选**:Copilot 的 `/rewind` 靠 `~/.copilot/session-state/<id>/rewind-snapshots/`(一个 `index.json` 加快照数据)撤销本会话的编辑。设 `BACKUP_EXCLUDE_REWIND=1` 把它们排除——省的空间比任何单项排除都多,且**不影响** `/share html`、`--resume`、`asmgr`(后两者从始终备份的 `events.jsonl` 重建);唯一失去的是对**恢复出来的**会话执行 `/rewind` 的能力。
|
|
291
|
-
|
|
292
|
-
### 端到端加密与架构
|
|
293
|
-
|
|
294
|
-
restic 跑在**客户端**,在数据离开主机前做**端到端 AES-256 加密**,再写入 **S3 兼容端点**(`RESTIC_REPOSITORY=s3:<endpoint>/<bucket>`;任何 restic 后端都行——rustfs / MinIO / SeaweedFS / AWS S3 / B2 / R2 / 本地路径 / sftp / rest)。后端只见密文,存储主机被攻破也不暴露你的历史。
|
|
295
|
-
|
|
296
|
-
反面:`RESTIC_PASSWORD` 是整个仓库**唯一**的钥匙——丢了它,所有快照永久不可读。`restic init` 后立刻把它抄进密码管理器 / 另一台设备。
|
|
297
|
-
|
|
298
|
-
到端点可能要过若干网络跳转(如 mesh 覆盖网 → 主机端口代理 → WSL2 端口转发 → 容器端口);这条跳转链是部署相关、含内网地址的,记在 `secrets.env` 头部注释里而**非**本文件——换机重新部署时只改 `secrets.env`,`backup.sh` / `exclude.txt` / 本文都是通用的。
|
|
299
|
-
|
|
300
|
-
### 配置与运行
|
|
301
|
-
|
|
302
|
-
复制模板、填入你自己的后端:
|
|
303
|
-
|
|
304
|
-
```bash
|
|
305
|
-
cp secrets.env.example secrets.env
|
|
306
|
-
chmod 600 secrets.env
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
必填变量:
|
|
310
|
-
|
|
311
|
-
| 变量 | 含义 |
|
|
312
|
-
|---|---|
|
|
313
|
-
| `RESTIC_REPOSITORY` | restic 仓库 URL,例如一个 S3 兼容桶 |
|
|
314
|
-
| `RESTIC_PASSWORD` | restic 仓库的加密口令 |
|
|
315
|
-
| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` | S3 凭据,仅 S3 兼容后端需要 |
|
|
316
|
-
|
|
317
|
-
可选变量:
|
|
318
|
-
|
|
319
|
-
| 变量 | 默认值 |
|
|
320
|
-
|---|---|
|
|
321
|
-
| `RESTIC_BIN` | `$HOME/.local/bin/restic` |
|
|
322
|
-
| `BACKUP_AGENT_DIRS` | `$HOME/.copilot:$HOME/.claude:$HOME/.codex` |
|
|
323
|
-
| `BACKUP_EXCLUDE_REWIND` | 未设置;设为 `1` 跳过 Copilot rewind 快照 |
|
|
324
|
-
|
|
325
|
-
首次初始化一个新的 restic 仓库:
|
|
326
|
-
|
|
327
|
-
```bash
|
|
328
|
-
set -a; source secrets.env; set +a
|
|
329
|
-
restic init
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
然后运行:
|
|
333
|
-
|
|
334
|
-
```bash
|
|
335
|
-
asmgr backup run --dry-run
|
|
336
|
-
asmgr backup run
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
把 `RESTIC_PASSWORD` 存进密码管理器或另一台设备。丢了它,加密备份就再也读不出来。
|
|
340
|
-
|
|
341
|
-
### 保留策略
|
|
342
|
-
|
|
343
|
-
每次运行给快照打 `agent-session-manager` + `$(hostname)` 标签,然后:
|
|
344
|
-
|
|
345
|
-
```
|
|
346
|
-
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
> 迁移注记:快照标签历经 `session-recall` → `agent-session-exporter` → `agent-session-manager`。若把新 checkout 指向已有仓库,先对齐标签(如 `restic tag --set agent-session-manager --tag agent-session-exporter`,或加匹配的 `--keep-tag`),让 `forget` 按预期血缘 prune、而非遗弃旧快照。
|
|
350
|
-
|
|
351
|
-
## 用 systemd 自动备份
|
|
352
|
-
|
|
353
|
-
示例 unit 文件在 `systemd/`:
|
|
354
|
-
|
|
355
|
-
```bash
|
|
356
|
-
mkdir -p ~/.config/systemd/user
|
|
357
|
-
cp systemd/agent-session-manager.service.example ~/.config/systemd/user/agent-session-manager.service
|
|
358
|
-
cp systemd/agent-session-manager.timer.example ~/.config/systemd/user/agent-session-manager.timer
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
编辑 `agent-session-manager.service`,把路径指向你的 checkout,然后:
|
|
362
|
-
|
|
363
|
-
```bash
|
|
364
|
-
systemctl --user daemon-reload
|
|
365
|
-
systemctl --user enable --now agent-session-manager.timer
|
|
366
|
-
systemctl --user list-timers agent-session-manager.timer
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
若希望登出后 timer 仍运行,请用你的系统管理员账户开启 user lingering。
|
|
370
|
-
|
|
371
|
-
> 只应有**一台**机器拥有该 timer。若从旧部署迁来(unit 曾指向别的 checkout、或快照打的是旧标签如 `session-recall`),先禁用并删掉旧 unit(`systemctl --user disable --now <old>.timer` 再删文件),以免跑两份备份或把保留血缘劈成两半。
|
|
372
|
-
|
|
373
389
|
## 目录结构
|
|
374
390
|
|
|
375
391
|
`asmgr` 是**一个** npm 包;下面的 `src/*` 是它的内部模块(相对 import 串联),不是各自发布的包。
|
|
@@ -383,7 +399,6 @@ systemctl --user list-timers agent-session-manager.timer
|
|
|
383
399
|
| `scripts` | esbuild 单文件打包、bun 原生二进制、构建期资源内联(gen-assets) |
|
|
384
400
|
| `fixtures` | 脱敏的解析器与 CLI fixtures |
|
|
385
401
|
| [`tools/copilot`](tools/copilot/) | Copilot `/share` bundle 漂移探针(仅逆向研究,非运行时依赖) |
|
|
386
|
-
| `backup.sh` | `asmgr backup` 用的 restic 封装 |
|
|
387
402
|
|
|
388
403
|
### <a id="drift-oracle"></a>漂移探针(`tools/copilot`)
|
|
389
404
|
|
|
@@ -395,9 +410,15 @@ node tools/copilot/extract-share-assets.cjs [path/to/@github/copilot/app.js] [ou
|
|
|
395
410
|
|
|
396
411
|
**为什么保留**:它是**漂移探针**。Copilot 升级可能改动时间线条目 / 筛选类、Primer 明暗主题规则、按钮 id 等 DOM 钩子。升级后重跑并 diff 上一次输出,把有意义的变化当作"复核离线事件映射与 React 渲染器"的提示,而不是自动搬进产物。维护中的 HTML 渲染器是 `src/html` 的 React 实现,不 import 也不发布这些抽取资产;仓库里目前没有大小 / 哈希基线,可在下次比较时记录探针打印的长度与本地校验和。
|
|
397
412
|
|
|
413
|
+
</details>
|
|
414
|
+
|
|
415
|
+
<details>
|
|
416
|
+
<summary>同类项目调研与差异</summary>
|
|
417
|
+
|
|
398
418
|
## 同类项目对比
|
|
399
419
|
|
|
400
|
-
|
|
420
|
+
这个问题空间已有多种 CLI、TUI、Web 与桌面实现。下表是 2026-07-24 整理文档时的调研快照;
|
|
421
|
+
Stars 只反映当时状态,不作为持续更新的排名。
|
|
401
422
|
|
|
402
423
|
| 仓库 | Stars | 语言 | 形态 | 覆盖 agent | 备注 |
|
|
403
424
|
|---|---:|---|---|---|---|
|
|
@@ -428,6 +449,11 @@ node tools/copilot/extract-share-assets.cjs [path/to/@github/copilot/app.js] [ou
|
|
|
428
449
|
|
|
429
450
|
这些灵感项都作为 GitHub issue 跟踪(每条写明 `Inspired by …`),见 [issues](https://github.com/TMYTiMidlY/agent-session-manager/issues):项目层级索引页(`claude-code-log`)、Token / 成本分析视图(`token-dashboard`)、实时 tail 模式(`claude-code-trace` / `tail-claude`)、按项目分组侧栏(`agent-session-viewer` / `codex-history-viewer`)、VS Code 扩展封装(`codex-history-viewer`)、Pages 静态导出 tarball(`claude-code-transcripts`)。
|
|
430
451
|
|
|
452
|
+
</details>
|
|
453
|
+
|
|
454
|
+
<details>
|
|
455
|
+
<summary>维护者:公开前安全检查</summary>
|
|
456
|
+
|
|
431
457
|
## <a id="safety"></a>公开前的安全检查
|
|
432
458
|
|
|
433
459
|
把本仓库推到任何公开位置前,只检查被跟踪的文件:
|
|
@@ -437,13 +463,15 @@ git ls-files
|
|
|
437
463
|
git grep -nE 'PRIVATE|SECRET|TOKEN|PASSWORD|AKIA|/(h[o]me|Users)/|10\\.|192\\.168\\.|172\\.|D[E]SKTOP|[Ww]orkstation'
|
|
438
464
|
```
|
|
439
465
|
|
|
440
|
-
`secrets.env`、`backup.log`、`node_modules
|
|
466
|
+
`secrets.env`、`backup.log`、`node_modules/` 与构建产物都被忽略,应保持未跟踪。
|
|
467
|
+
|
|
468
|
+
</details>
|
|
441
469
|
|
|
442
470
|
## <a id="roadmap"></a>路线图
|
|
443
471
|
|
|
444
472
|
待办与灵感项都在 [GitHub issues](https://github.com/TMYTiMidlY/agent-session-manager/issues) 跟踪。两条值得单独点名的方向:
|
|
445
473
|
|
|
446
|
-
- **忠实恢复 / 迁移**:把会话恢复到"另一台机器能 `--resume`"的原生状态(来源 = 备份快照 ∪
|
|
447
|
-
- **本地 Web 界面 `asmgr web
|
|
474
|
+
- **忠实恢复 / 迁移**:把会话恢复到"另一台机器能 `--resume`"的原生状态(来源 = 备份快照 ∪ 另一台机器)——边界见 [ADR 0001](docs/adr/0001-scope-archive-and-restore.md)。
|
|
475
|
+
- **本地 Web 界面 `asmgr web`**:本机启动、仅供自己查看的会话浏览界面。
|
|
448
476
|
|
|
449
|
-
单文件分发与 npm 发布**已实现**(单一无 scope 包 `asmgr`、四平台原生二进制、semantic-release、`npm i -g github:` 免 registry 安装)——详见[安装](#install)
|
|
477
|
+
单文件分发与 npm 发布**已实现**(单一无 scope 包 `asmgr`、四平台原生二进制、semantic-release、`npm i -g github:` 免 registry 安装)——详见[安装](#install)。其余(持久化索引外部会话目录、提升适配器保真度、项目层级索引页、Token / 成本视图、实时 tail、VS Code 扩展、Pages 导出 tarball、跨多会话仪表盘)见 issues。
|