Skip to content

v1.3.8: browse Qoder sessions in the conversation view - #35

Merged
loadchange merged 13 commits into
mainfrom
claude/qoder-tool-integration-vkbjvx
Aug 5, 2026
Merged

v1.3.8: browse Qoder sessions in the conversation view#35
loadchange merged 13 commits into
mainfrom
claude/qoder-tool-integration-vkbjvx

Conversation

@loadchange

Copy link
Copy Markdown
Collaborator

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/projects consumption).

🤖 Generated with Claude Code

https://claude.ai/code/session_01QKBKf3mFPbAXipL2bJF4oF


Generated by Claude Code

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 qoder module 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.

Comment thread src-tauri/src/history.rs Outdated
Comment on lines 600 to 604
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()));
}
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/renderer/conversations.js Outdated
Comment on lines +605 to +610
const kind = loadError && loadError.kind;
const key = kind === 'permissionDenied'
? 'conv.permissionDenied'
: !loadError || kind === 'notFound'
? 'conv.notFound'
: 'conv.readFailed';

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_injected is documented as “MUST stay rule-for-rule in sync” with the renderer/export versions, but it doesn’t implement the formatCodexBootstrap(...) transformation that src/renderer/conversations.js and src/main/export-assets/runtime.js now 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. Since qoder::read_text is 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);

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.credits label 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.credits label 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.credits label 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.credits label untranslated (Credits), which produces mixed-language UI strings.
    'conv.stat.credits': 'Credits',

src/renderer/input.css:1387

  • .skill-snapshot > summary disables 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 > summary disables 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.credits label 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.credits label 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.credits label 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.credits label 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

Copy link
Copy Markdown
Collaborator Author

Addressed the latest two Copilot reviews in 6de81fb:

  • strip_injected bootstrap parity (review on 49e5357): ported formatCodexBootstrap to the Rust search extractor with the same rule order, so search indexes the exact Markdown the panel renders; covered by strip_injected_formats_codex_bootstrap_like_the_panel.
  • Untranslated conv.credits / conv.stat.credits: now 积分 / 點數 / クレジット / 크레딧 in zh-CN / zh-TW / ja / ko.
  • .skill-snapshot > summary outline: none: removed in input.css and the compiled styles.css — keyboard focus indicator restored (browsers only paint it for keyboard focus).

Not changed — usage.rs lossy UTF-8 for qoder: intentional. The usage module reads lossily everywhere by design (LossyLines does per-line from_utf8_lossy, locked in by the invalid_utf8_does_not_truncate_a_file test) so one corrupt byte can't erase a whole file's token history. The qoder branch mirrors the exact split Claude files already have: strict reads for display (read_text), lossy for usage aggregation. Making qoder strict here would drop entire files from 用量 on a single bad byte — a regression relative to Claude parity.


Generated by Claude Code

@loadchange
loadchange merged commit f917bed into main Aug 5, 2026
3 checks passed
@loadchange
loadchange deleted the claude/qoder-tool-integration-vkbjvx branch August 5, 2026 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants