Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
a1465bd
fix: 快照比对行尾无关化(CRLF折叠LF)修复 autocrlf 物化击穿 | 决策: Verifier两侧归一化+gitattri…
liuqihonggit Oct 20, 2026
7a6dbe6
feat: Demo演示命令路由md/diff/perm/all+权限请求事件 | 决策: TurnScript四值脚本按命令分派(未知命…
liuqihonggit Oct 20, 2026
5c1c6a2
fix: diff红绿行被2行预览折叠吞掉致真实终端无红绿 | 决策: 预览上限2→10对齐基准update全量渲染diff先例(File…
liuqihonggit Oct 20, 2026
ade1e34
docs: TASK055 追加 M7-4b 验收反馈修复决策块(diff红绿根因=预览折叠吞行) | 决策: 验收表步骤3同步更新着色可…
liuqihonggit Oct 20, 2026
96cc036
docs: M7-5 代码高亮调研落地(基准双引擎真相+C#三方案对比) | 决策: 推荐TextMateSharp路线=基准Rust原版…
liuqihonggit Oct 20, 2026
5ddfb71
feat: M7-5 高亮AOT探针通过(TextMateSharp+Onigwrap原生链NativeAOT实测) | 决策: 用户选定…
liuqihonggit Oct 20, 2026
c006ca3
feat: M7-5 高亮引擎落地(TextMateCodeHighlighter卫星实现+Core插件接口) | 决策: Core只定义…
liuqihonggit Oct 20, 2026
24de055
feat: 输入历史环纯逻辑(容量100+草稿暂存/恢复+不回绕导航) | 决策: 对齐useArrowKeyHistory状态机,ind…
liuqihonggit Oct 20, 2026
3d6e6ed
feat: 斜杠命令补全过滤排序状态机 | 决策: 二级排序精确名>精确切名>前缀>子序列(简化Fuse),Esc抑制同输入,循环导航
liuqihonggit Oct 20, 2026
3d1ddf1
feat: 建议列表渲染组件(6条可见+两列固定列宽+选中居中滚动窗口) | 决策: 选中Suggestion色未选中dim,列宽由调用方…
liuqihonggit Oct 20, 2026
123cab8
feat: ReplShell/ReplView补全与历史集成(键位仲裁+建议区渲染) | 决策: HandleKey文本变化才刷新防导航…
liuqihonggit Oct 20, 2026
fa7d2ee
feat: Host组装命令清单与历史种子注入 | 决策: DI解析Catalog兜底直接实例化生成目录,历史从sessions tran…
liuqihonggit Oct 20, 2026
5210c42
fix: 建议状态同步先于EnsureScreens(修复建议激活首帧屏高滞后一帧裁剪) | 决策: 提取SyncSuggestionSt…
liuqihonggit Oct 20, 2026
dfadac8
feat: M7-5 Core渲染链接线代码高亮插件 | 决策: LayoutWithHighlights双入口保留旧Layout兼容,布…
liuqihonggit Oct 20, 2026
1bf09a3
docs: TASK056验收表与决策记录(634+43回归基线+已知简化清单)
liuqihonggit Oct 20, 2026
9049483
feat: Demo接入TextMate代码高亮器(M7-5验收面) | 决策: 交互与bridge两处ReplShell构造均注入Tex…
liuqihonggit Oct 20, 2026
88ed60d
docs: TASK055 M7-5 落地决策块(4commit链+四列验收表+TextMateSharp API实证)
liuqihonggit Oct 20, 2026
2941965
feat: Demo接线斜杠补全(演示命令清单注入)+SimulatedEngine兼容/前缀路由 | 决策: ParseCommand …
liuqihonggit Oct 20, 2026
8ae2b59
docs: TASK056补充Demo验收入口接线记录
liuqihonggit Oct 20, 2026
c63b6bc
docs: TASK055 M7-6 模型列表调研块(基准真相+引擎侧资产盘点+方案ABC对比)
liuqihonggit Oct 20, 2026
0178239
docs: TASK056完结(用户Demo+Host双入口手动验收通过)
liuqihonggit Oct 20, 2026
05fabd6
feat: M7-6 模型选择器Core层(全部自研) | 决策: ModelPickerCoordinator状态机(Begin焦点定位…
liuqihonggit Oct 20, 2026
d049fb8
feat: TranscriptFileWriter改JSONL纯追加+逐行流式读 | 决策: 新增TranscriptJsonlCont…
liuqihonggit Oct 20, 2026
42a2268
feat: TranscriptService/AgentTranscriptService切换jsonl路径+流式preview+双源迁…
liuqihonggit Oct 20, 2026
fb56b1e
feat: M7-6 模型选择器 Host/Demo 接线 | 决策: Host 从引擎 IModelCatalog 后端获取清单,App…
liuqihonggit Oct 20, 2026
f4d7c65
docs: TASK055 M7-6 模型选择器落地决策块(四列验收表+基准对齐核对+自研决策记录)
liuqihonggit Oct 20, 2026
49bc9a1
docs: TASK055 M7-7 多子代理分组调研块(基准组头三态+逐行机制+分组键messageId真相+本项目八色板/ModelP…
liuqihonggit Oct 20, 2026
ec6ec6f
docs: ADR 0144 accepted+TASK057任务1完结(真实存量会话迁移验收记录)
liuqihonggit Oct 20, 2026
8a13dad
feat: M7-7 子代理分组Core层(组头三态+逐代理两行式+可见窗口) | 决策: SubagentGroupCoordinato…
liuqihonggit Oct 20, 2026
9bd5061
feat: M7-7 agents演示脚本+Demo接线 | 决策: SimulatedEngine加Subagents脚本走独立并行子回…
liuqihonggit Oct 20, 2026
a212f26
docs: TASK055 M7-7 多子代理分组落地决策块(四列验收表+基准对齐偏离表+Host接线后置记录)
liuqihonggit Oct 20, 2026
813a509
fix: EnsureSessionAsync测试断言切jsonl路径 | 决策: rebase集成时自动合并保留上游transcript…
liuqihonggit Oct 20, 2026
b6f4309
feat: TUI参数补全Argument模式 | 决策: CommandSuggestion加ArgumentHint/Argument…
liuqihonggit Oct 20, 2026
c41a369
feat: TUI幽灵文本补全 | 决策: GhostSuffix取最后空白后/查询的首个前缀匹配命令剩余段,下拉互斥,RightArro…
liuqihonggit Oct 20, 2026
dd91bd1
feat: M7-7 组头●闪烁动画(600ms方波+时钟广播) | 决策: IAnimatable接口+ReplShell每拍广播(基准…
liuqihonggit Oct 20, 2026
bde7f49
docs: TASK055 M7-7 组头闪烁落地记录(偏离表更新+四列验收表补广播/闪烁行+遗留项重排)
liuqihonggit Oct 20, 2026
061d4f2
feat: TUI历史反向搜索Ctrl+R | 决策: HistorySearch状态机(子串匹配+文本去重+容量100+新→旧),搜索态…
liuqihonggit Oct 20, 2026
23fe4a4
feat: resize事件化(ITerminalSizeSource注入) | 决策: 尺寸源抽象+Console轮询默认实现(基准us…
liuqihonggit Oct 20, 2026
2b35dec
docs: TASK055 resize事件化落地记录(四列验收表补尺寸源行+决策块+遗留项更新)
liuqihonggit Oct 20, 2026
5d2555d
feat: Demo接线参数补全演示(theme参数+model提示) | 决策: SimulatedEngine兼容/theme/mod…
liuqihonggit Oct 20, 2026
12aa340
docs: TASK057四任务完结记录(基线751+45+Demo双自检)
liuqihonggit Oct 20, 2026
0e19963
fix: 参数补全值域双源消除(修复/theme d验收缺陷) | 决策: SlashCommandMetadata加Arguments字…
liuqihonggit Oct 20, 2026
e7d92f4
fix: CI组件包缓存陈旧致CS0117 | 决策: setup-test-env下载artifact后删.nuget/packages…
liuqihonggit Oct 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,9 @@
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

###############################################################################
# 快照基线字节稳定 — approved 快照含 ANSI 控制序列且比对期望 LF 行尾,
# 钉死 eol=lf 防 autocrlf 物化改写字节(stash/checkout 周期免疫)
###############################################################################
*.approved.txt text eol=lf
19 changes: 19 additions & 0 deletions .github/actions/setup-test-env/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,25 @@ runs:
name: ${{ inputs.nuget-artifact-name }}
path: artifacts/nuget/

# NuGet 缓存 key 只哈希 csproj+props,不含 .cs 源码 — 只改源码的 PR 会命中旧缓存里的
# 过期 JoinCode 组件包(版本恒 1.0.0 无法靠版本号辨新旧),而源码生成器(analyzer 恒新)
# 输出引用新 API → CS0117 编译错。删缓存里的自家组件包强制从 local-feed(本次 pack 的
# 最新 artifact)重解析;第三方大包(网络下载大头)缓存照常命中,仅本地磁盘重拷秒级。
- name: Purge Stale JoinCode Component Packages from Cache
shell: pwsh
run: |
$pkgRoot = Join-Path $env:GITHUB_WORKSPACE ".nuget" "packages"
if (Test-Path $pkgRoot) {
$stale = Get-ChildItem -Path $pkgRoot -Directory -Filter "joincode.*"
if ($stale) {
$stale | ForEach-Object { Write-Host "purging: $($_.Name)" }
Remove-Item -Path $stale.FullName -Recurse -Force
Write-Host "Purged $($stale.Count) JoinCode package(s) — restore re-resolves from local feed (latest pack)"
} else {
Write-Host "No JoinCode packages in cache — nothing to purge"
}
}

- name: Add Local NuGet Feed
shell: pwsh
run: |
Expand Down
50 changes: 50 additions & 0 deletions docs/proposed/adr/0144-transcript-jsonl-append-streaming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# ADR 0144: 会话转录存储 JSON 数组改 JSONL 纯追加(按需流式读取)

- 状态:accepted(2026-10-21 落地验证:单元 86 + 集成 2 + 真实存量会话迁移验收 OK;写入侧经真实引擎链路产出 transcript.jsonl 确认)
- 日期:2026-10-21
- 决策者:liuqihong(用户指令:会话改 jsonl 按需读取和追加,现在逻辑有问题)

## 背景

### 问题:transcript.json 整存整取

当前 `~/.jcc/sessions/{id}/transcript.json` 是 JSON 数组格式,`TranscriptFileWriter` 的追加路径(`AppendEntryInternalAsync`/`AppendEntriesInternalAsync`)是"读旧数组 → Add → 写回全量":

- **写入 O(n)**:每轮对话结束(`TranscriptPersistMiddleware` 差量落盘)都要全量读取 + 全量重写文件。大会话(数百条目 × 长内容)每轮提交代价线性增长,且全量重写有写入中途崩溃损坏整个文件的风险。
- **读取 O(全量)**:`ListTranscriptsAsync`(GUI 侧栏/`/resume`/TUI HistorySeeder 高频调用)为了提取 entryCount + 最后一条 preview,全文 `ReadToEndAsync` + 整体反序列化整个数组。
- `GetCustomTitleAsync` 同样全量加载后倒序扫一条元数据。

### 历史演进的两次反向决策(需正面回应)

| Commit | 决策 | 动机 | 本次重新评估 |
|--------|------|------|-------------|
| #126(9a8bd2172) | JSONL → JSON 数组 | 人类可读(WriteIndented)+ 层次化目录 + 可读会话 ID | 目录组织与会话 ID **已保留且不变**;"人类可读"降级诉求(每行一条紧凑 JSON 仍可读)不足以抵消 O(n) 写入 |
| #163(b9b2ca711) | .jsonl 扩展名统一为 .json | 扩展名统一 | 恢复 `.jsonl` 名实相符;#163 的 55 处替换是格式随扩展名的联动,本次格式真的变了,名不符实(.json 文件装 JSONL 行)反而误导工具与人 |

### JSONL 时代的两个已记录坑(规避方案现成)

- FileMode.Append 文件不存在抛异常(PhysicalTests 考古)→ 用 `FileMode.OpenOrCreate + Seek(End)`
- 跨进程读-写冲突(#74 集群 E2E)→ 沿用 `FileShare.ReadWrite` 流读写(git show a924418df 版实现)

## 决策

**transcript 存储从 JSON 数组整存整取改为 JSONL 每行一条纯追加 + 按需流式读取。**

1. **写入 O(1) 纯追加**:`FileMode.OpenOrCreate + Seek(End)` 批量写行(`RelaxedJsonSerializer.Serialize(entry, TranscriptJsonContext.Default.TranscriptEntry)` 紧凑单行 + '\n');Actor 邮箱串行化保留;`MaybeOffloadToPasteStore` 卸载逻辑不变(逐条落盘前生效)。
2. **读取逐行流式**:`ReadLinesAsync` 逐行反序列化 + `ResolveFromPasteStore` 还原;`LoadTranscriptAsync` 聚合(接口语义不变);`ListTranscriptsAsync` 只数行数 + 解析尾行提 preview(不再全文反序列化)。
3. **新文件名 `transcript.jsonl`**;读取兼容回退:`.jsonl` 不存在时读存量 `transcript.json`(数组格式旧逻辑)——存量会话零迁移可用。
4. **迁移幂等不删旧文件**(沿 MigrateLegacyAsync 红线):启动时把 ①旧扁平 `{id}.json`(JSONL 行)②子目录 `{id}/transcript.json`(数组)统一迁移到 `{id}/transcript.jsonl`;目标存在跳过。
5. **改动封闭**:全部消费方(CLI/GUI/TUI 三端 + ForkCommand/ResumeCommand/子代理)经 `ITranscriptService`/`IAgentTranscriptService` 抽象,接口签名零变更;改动封闭在 `TranscriptFileWriter` + `TranscriptService`(路径/preview/迁移)+ `AgentTranscriptService`(子代理路径)内部。

## 替代方案(考虑过但放弃)

- **保持 JSON 数组 + 内存缓存增量写**:写入仍需全量重写(崩溃窗口),且缓存丢失即丢数据;不解决 ListTranscripts 全量读。
- **SQLite**:引入原生依赖(违反 NativeAOT 约束偏好),杀鸡用牛刀。
- **保持 .json 文件名装 JSONL 内容**:名不符实,误导工具链与后续维护者。

## 影响面

- 约 10 个直接断言磁盘字节格式的测试用例随格式重写(TranscriptServiceTests/TranscriptFileWriterPasteStoreTests)。
- `HousekeepingService` 按 mtime 清理,格式无关,零影响。
- meta.json / usage-facet.json / diag / tool-results 与 transcript.json 零耦合,零影响。
- 集成测试 `TranscriptPersistIntegrationTests` 走 service API,是最接近真实落盘语义的回归防线。
Loading