v1.3.8: browse Qoder sessions in the conversation view - #35
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QKBKf3mFPbAXipL2bJF4oF
There was a problem hiding this comment.
Pull request overview
This PR adds first-class support for browsing Qoder CLI sessions in CC Buddy’s conversation (“对话”) view, including safe/guarded reads of Qoder’s Claude-like JSONL transcripts, subagent parsing, HTML export branding, and app-owned metadata (title/tags/soft-delete) stored in the shared sidecar without rewriting Qoder’s files.
Changes:
- Introduces a new Tauri-side
qodermodule with strict path validation, bounded reads, macOS helper fallback for “Other Application Data”, and transcript normalization (atomic assistant wrappers, queued commands). - Extends session listing/detail/search/export pipelines to route Qoder sessions as a distinct source (
source: "qoder") while preserving “never hard-delete another tool’s files”. - Updates renderer behavior (source label, error handling + retries) and adds styling for inline subagent bodies; bumps app version to 1.3.8 and adds macOS usage description.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/shared/i18n-dict.js | Adds new localized strings for permission-denied and read-failed session loads. |
| src/renderer/styles.css | Compiled Tailwind output updated to include .subagent-inline-body styling. |
| src/renderer/input.css | Tailwind source updated to define .subagent-inline-body styling. |
| src/renderer/conversations.js | Adds qoder source naming and improves detail loading with request coalescing + error/retry handling. |
| src-tauri/tauri.conf.json | Bumps Tauri app version to 1.3.8. |
| src-tauri/src/store.rs | Auto-detects ~/.qoder and ~/.qoderwork and seeds them into historyDirs. |
| src-tauri/src/qoder.rs | New module: Qoder root detection, guarded reads (macOS helper fallback), record normalization, and sidecar metadata integration. |
| src-tauri/src/lib.rs | Wires the new module and updates raw export to use guarded session-byte reads. |
| src-tauri/src/history.rs | Routes Qoder sessions through normalization + sidecar metadata; adds structured read errors and export/read-path changes. |
| src-tauri/src/exporthtml.rs | Adds Qoder-aware JSONL parsing/normalization and exports branded as “Qoder”. |
| src-tauri/Info.plist | Adds NSAppDataUsageDescription for macOS privacy prompt copy. |
| src-tauri/Cargo.toml | Bumps Rust crate version to 1.3.8. |
| src-tauri/Cargo.lock | Updates lockfile for the version bump. |
| package.json | Bumps npm package version to 1.3.8. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if built.get("readError").map(Value::is_null).unwrap_or(true) { | ||
| if let Ok(mut cache) = meta_cache().lock() { | ||
| cache.insert(file.to_path_buf(), (mt, size, built.clone())); | ||
| } | ||
| } |
There was a problem hiding this comment.
Fixed in 9c464d4 — only permissionDenied rows skip the memo now; other read errors are cached and invalidated by the mtime/size key like normal rows.
Generated by Claude Code
| const kind = loadError && loadError.kind; | ||
| const key = kind === 'permissionDenied' | ||
| ? 'conv.permissionDenied' | ||
| : !loadError || kind === 'notFound' | ||
| ? 'conv.notFound' | ||
| : 'conv.readFailed'; |
There was a problem hiding this comment.
Fixed in 9c464d4 — the macOS System Settings copy is now shown only on macOS (navigator.platform check); other platforms fall back to the generic conv.readFailed message, which keeps the retry timer armed.
Generated by Claude Code
…y per review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QKBKf3mFPbAXipL2bJF4oF
…d reads, search strip parity, normalized imports, retry backoff Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QKBKf3mFPbAXipL2bJF4oF
….com/ccbud/ccbud into claude/qoder-tool-integration-vkbjvx
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QKBKf3mFPbAXipL2bJF4oF
…ud/ccbud into claude/qoder-tool-integration-vkbjvx
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 21 changed files in this pull request and generated no new comments.
Suppressed comments (2)
src-tauri/src/history.rs:1276
strip_injectedis documented as “MUST stay rule-for-rule in sync” with the renderer/export versions, but it doesn’t implement theformatCodexBootstrap(...)transformation thatsrc/renderer/conversations.jsandsrc/main/export-assets/runtime.jsnow apply before stripping XML envelopes. This makes global search text diverge from what the conversation panel shows for Codex AGENTS bootstrap messages (and the comment is currently inaccurate). Consider porting the bootstrap formatting step into this Rust function (or remove it from the JS versions if you don’t want it searchable/rendered differently).
/// Strip harness-injected blocks from user prose — MUST stay rule-for-rule in sync with the
/// renderer's stripInjected (conversations.js) and the export viewer's copy (runtime.js), so what
/// the big search matches is exactly what the in-conversation search (and the panel) will show.
/// Task-notification envelopes keep their human-facing <result> body; the transport metadata
/// (ids, status, summary) is dropped and must therefore never be searchable.
src-tauri/src/usage.rs:517
- This path decodes Qoder transcripts with
String::from_utf8_lossy, which can silently replace invalid bytes and change how records parse / get counted. Sinceqoder::read_textis explicitly strict UTF-8 (and the transcript format is defined as UTF-8), usage aggregation should use the strict text reader too and skip/count failures consistently.
if crate::qoder::looks_qoder_path(&file) {
let Ok(bytes) = crate::qoder::read_bytes(&file) else { continue };
for line in String::from_utf8_lossy(&bytes).lines() {
if let Some(rec) = parse_claude_line(line.trim()) {
claude_recs.push(rec);
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated no new comments.
Suppressed comments (10)
src/shared/i18n-dict.js:811
- The zh-CN locale leaves the new
conv.stat.creditslabel untranslated (Credits), which produces mixed-language UI strings.
'conv.stat.credits': 'Credits',
src/shared/i18n-dict.js:1252
- The zh-TW locale leaves the new
conv.stat.creditslabel untranslated (Credits), which produces mixed-language UI strings.
'conv.stat.credits': 'Credits',
src/shared/i18n-dict.js:1702
- The ja locale leaves the new
conv.stat.creditslabel untranslated (Credits), which produces mixed-language UI strings.
'conv.stat.credits': 'Credits',
src/shared/i18n-dict.js:2152
- The ko locale leaves the new
conv.stat.creditslabel untranslated (Credits), which produces mixed-language UI strings.
'conv.stat.credits': 'Credits',
src/renderer/input.css:1387
.skill-snapshot > summarydisables the browser focus outline (outline: none), which makes the Skill snapshot disclosure hard to use via keyboard navigation. Removing this line restores the default focus indicator.
cursor: pointer;
list-style: none;
outline: none;
color: var(--muted);
src/renderer/styles.css:4261
.skill-snapshot > summarydisables the browser focus outline (outline: none), which makes the Skill snapshot disclosure hard to use via keyboard navigation. Removing this line restores the default focus indicator.
cursor: pointer;
list-style: none;
outline: none;
color: var(--muted);
src/shared/i18n-dict.js:755
- The zh-CN locale leaves the new
conv.creditslabel untranslated (Credits), which produces mixed-language UI strings.
This issue also appears on line 811 of the same file.
'conv.credits': 'Credits',
src/shared/i18n-dict.js:1196
- The zh-TW locale leaves the new
conv.creditslabel untranslated (Credits), which produces mixed-language UI strings.
This issue also appears on line 1252 of the same file.
'conv.credits': 'Credits',
src/shared/i18n-dict.js:1646
- The ja locale leaves the new
conv.creditslabel untranslated (Credits), which produces mixed-language UI strings.
This issue also appears on line 1702 of the same file.
'conv.credits': 'Credits',
src/shared/i18n-dict.js:2096
- The ko locale leaves the new
conv.creditslabel untranslated (Credits), which produces mixed-language UI strings.
This issue also appears on line 2152 of the same file.
'conv.credits': 'Credits',
…redits labels, restore summary focus outline Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QKBKf3mFPbAXipL2bJF4oF
|
Addressed the latest two Copilot reviews in 6de81fb:
Not changed — Generated by Claude Code |
Adds Qoder to the 对话 view: auto-detects
~/.qoder/~/.qoderwork, parses its Claude-format transcripts (incl. subagents, search, HTML export) with Qoder branding, keeps title/tags/soft-delete in the app sidecar, and never rewrites or hard-deletes another tool's files (modeled after agentsview's~/.qoder/projectsconsumption).🤖 Generated with Claude Code
https://claude.ai/code/session_01QKBKf3mFPbAXipL2bJF4oF
Generated by Claude Code