Files
yetone 4eba5c37a8 sessions: ZCode, DeepSeek Harness, Cline and Qoder's sessions are listed too (lml: 希望会话里也能看到 ZCode、Qoder CN、Cline、DeepSeek Harness 的) — ZCode's are OpenCode's tables in ~/.zcode/cli/db/db.sqlite, read as OpenCode's database is (opened read-only), its tokens the AI SDK's (input less the cache, output as it is), its model modelId, a title_source of default no title, a prompt typed a real_user's; dsh's are ~/.dsh/sessions ($DSH_HOME), a folder a session, the latest format's session[.vN].jsonl[.zstd] read whole, zstd frames and all, a subagent's (parentSession) in its parent's, a fork's seeded events (seedLength, or up to an inherited session/end-seed) counted where they were first written; Cline's are ~/.cline/data/sessions ($CLINE_SESSION_DATA_DIR, $CLINE_DATA_DIR, $CLINE_DIR), <id>.messages.json with its manifest <id>.json for the cwd, the prompt and the title, a subagent's other messages file beside it, a fork's messages before its forkedAt not counted, cline --id <id> to pick it up; Qoder's and Qoder CN's are Claude Code's lines in ~/.qoder/projects and ~/.qoder-cn/projects ($QODER_CONFIG_DIR, $QODERCN_CONFIG_DIR), qodercli --resume / qoderclicn --resume. Each folder is watched when it's there (Dirs). Tests keep HOME in their sandbox now. Tested with made-up fixtures for each (a ZCode database made in the test, dsh plain and zstd, forks of both formats, a Cline fork and subagent, both Qoder builds), and read-only against copies of this machine's ZCode database and dsh sessions: 2 and 13 sessions, their token totals the same as a separate tally of the raw rows
2026-09-28 22:45:50 +08:00

47 lines
1.6 KiB
Go

package sessions
import (
"os"
"path/filepath"
)
// ZCode's CLI, OpenCode made over, keeps its sessions in OpenCode's tables
// in a database of its own, ~/.zcode/cli/db/db.sqlite: a session row with
// how its title came about (title_source), and its messages and parts as
// JSON documents. A message counts as OpenCode's does but for its tokens,
// the AI SDK's: input with the cache in it, output with the reasoning. Its
// model is modelId (the older ones say modelID too), and a user message
// says who it is from (semantics.origin), a prompt typed a real_user's. A
// subagent's work is a session whose parent is the one it ran in, as in
// OpenCode. ZCode is a desktop app: no command picks a session up again.
// ZCodeDir is ZCode's folder, ~/.zcode.
func ZCodeDir() string {
home, _ := os.UserHomeDir()
return filepath.Join(home, ".zcode")
}
func zcodeDB() string { return filepath.Join(ZCodeDir(), "cli", "db", "db.sqlite") }
func zcodeFiles() []file {
if db := zcodeDB(); fileExists(db) {
return openCodeDBFiles("zcode", db)
}
return nil
}
// zcDB is ZCode's database: OpenCode's, with a session's title its own only
// when it was not the default one.
type zcDB struct{ ocDB }
func (s zcDB) info(sid string) (ocInfo, bool) {
var i ocInfo
var source string
err := s.db.QueryRow(`SELECT id, COALESCE(parent_id, ''), directory, title, COALESCE(title_source, ''), time_created, time_updated FROM session WHERE id = ?`, sid).
Scan(&i.ID, &i.ParentID, &i.Directory, &i.Title, &source, &i.Time.Created, &i.Time.Updated)
if source == "default" {
i.Title = ""
}
return i, err == nil
}