feat(session): cross-platform session migration and team session archive - #593
Open
lurkacai0831 wants to merge 8 commits into
Open
lurkacai0831 wants to merge 8 commits into
lurkacai0831 wants to merge 8 commits into
Conversation
added 8 commits
September 16, 2026 18:39
- new codebuddy-ide adapter: list/read/write/delete for the IDE sidebar history store (previously write-only via the cli adapter's implicit double-write, so IDE sessions could neither be listed nor migrated) - cli adapter no longer writes/deletes the IDE store; read/write symmetry - detect both on-disk history layouts (default instance stores history one level higher) so its conversations are no longer skipped - reuse 32-hex conversation ids as-is instead of hashing twice, fixing rollback reporting success while leaving sessions in place - encode cli project dirs with CodeBuddy's own rule (spaces kept), so workspaces like 'teamai cli' can be listed and read - resolve symlinks before hashing workspaces (/tmp vs /private/tmp) - shared title cleaning: skip <system-reminder>-style injected first messages instead of leaking prompt text into listings - user-facing errors and test assertions in English
…rectness fixes M1 correctness: - migrate --push re-reads exactly the migrated target session ids instead of 'the N most recent', which could push unrelated sessions - meta no longer lies: fidelityScore uses the real preview score and createdAt records the session's own creation time, not push time - resume failures hint that the session may be archived under another project identity (search --all / --cwd) - empty pushes no longer report success when nothing was committed - 14 Chinese user-facing strings converted to English M2 user-repo capability: - SyncManager: listAllRepoIdentities() reverse-maps canonical identities from each repo's _index.json; listSessionsAcrossRepos() merges entries - list --all / pull --all / search --all give the cross-project view (search --all previously had a dead loop and never searched other repos) - push --all archives every workspace of one platform (--source), confirming before pushing more than 5 sessions (-y skips) - archive key derives from the session's native cwd instead of the directory the command ran in; unknowable workspaces (codebuddy-ide md5 placeholders) archive under _unattributed with a warning - claude-code / codebuddy / cursor readSession recover the native cwd from the first JSONL record instead of lossy directory-name decoding - pushing the same session twice updates the entry instead of creating _1 duplicates (dedup key: origin sessionId + author)
…red fixes Tests (29 new cases): - session-sync.test.ts: identity reverse-mapping, cross-repo listing, dedup by origin sessionId, index rebuild round-trip - session-cmd.test.ts: list/pull/search --all, push --all confirmation, native archive key, English output assertions Docs: - usage-guide (en/zh): new Session Sync & Migration section - README (en/zh): capability row and command cheat-sheet entries - CHANGELOG: M1/M2 entries plus the fixes below Fixes found by the real-CLI E2E run: - encode symlink-resolved cwds into project directory names for claude-code / codebuddy / cursor / workbuddy (writing /tmp/x used to create a directory listing from /private/tmp/x could never see) - keep the local commit and print a warning when the remote push fails instead of crashing after a successful save - apply the shared injected-title cleaning to claude-code / workbuddy / cursor (their first 'user message' is often a system-reminder wrapper, which used to become the archived session name)
Claude Code's /resume picker shows the bare session id (e.g. 824ff784) for sessions without a type:"summary" record, so every migrated session appeared untitled. Carry the IR session title — already cleaned of injected wrappers by the source adapter — into the target JSONL.
…ommands From the three-way QA sweep (adapters / command layer / fidelity): P0 crashes fixed (found by real-CLI execution): - git add/commit/pull in a non-git or missing --repo-root dumped a full stack trace with internal paths; now a one-line error + exit 1 - concurrent pushes hitting git index.lock crashed the same way - pull with no origin remote / nonexistent repo root reported a misleading ENOENT instead of the actual cause Correctness: - session archive dedup key now includes platform: a session pushed as codebuddy and re-archived after migrating to claude-code are two artifacts, not an update of each other - codex keeps per-message timestamps (read response_item.timestamp, stamp records with the message's own time) — roundtrips no longer collapse the timeline - codex session lookup matches whole ids; a 4-char prefix could resolve to someone else's session file - cursor writeSession is idempotent again (malformed UUID regex minted a new id per write, piling up copies) - claude-code readSession honors the type:"summary" record it writes - workbuddy/claude-code/cursor titles skip injected ai-title/name wrappers and tool-output snippets; extractMeta no longer stops at the first injected block (real question after a system-reminder wrapper becomes the title) - codex writeSession survives an invalid session.createdAt instead of crashing with RangeError - a corrupted sessions/**/_index.json warns with the rebuild command instead of silently emptying the dedup key Robustness: - interactive prompts treat EOF like "n" (Cancelled., exit 0) instead of a silent success; --limit rejects non-positive values; a closed output pipe exits cleanly instead of an EPIPE stack - remote push failures report git's actual fatal line, keeping the local commit Docs: - design doc gains a Known limitations section (fidelityScore is a proxy metric; codex splitting; sessionId is platform-native; flattenDag) - src/__tests__/fidelity-sweep.test.ts joins the suite as the fidelity regression tool (roundtrip matrix over 5 platform routes)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #587
Adds two layers to
teamai session: cross-platform session migration (move a full conversation between AI tools, previewable and undoable) and a team session archive (archive into the team repo, search, restore).What ships
Migration
session platformssession migrate <id> -s <src> -t <dst>--allfor the recent fewsession rollback <id> --platform <dst>Team archive
session push --source <agent>--allcovers every workspace of that agentsession pullsession list/list --all--alladds a SOURCE column)session search <kw> --allsession resume <name> --platform <agent>Platforms:
claude-code,codebuddy(CLI),codebuddy-ide(IDE sidebar),codex,cursor,workbuddy, plus theclaude-internal/tclaude/codex-internal/tcodexvariants.Design notes
sessions/repos/<repo>/<author>/is keyed on the git identity of the session's own working directory (recovered from the JSONL record where needed); unknowable workspaces (codebuddy-ide md5 placeholders) land in_unattributedwith an English warning. Runningpushfrom another directory still archives under the right project.rollback, nobody dares migrate anything real.--all— a project team repo shows only its own sessions; a personal repo gets the cross-project view.session save(scrubbed summary → digest) rather than replacing it: summary for trends, full session for resuming.Known limitations are documented in
docs/designs/session-user-repo-sync.md— notably thatfidelityScoreis a proxy for IR-block degradation, not a byte-equality guarantee.Test plan (all executed against the built CLI)
npx tsc --noEmit→ 0 errors ✅npx vitest run src/__tests__/session-{sync,cmd}.test.ts src/__tests__/{codebuddy-ide-adapter,session-title,fidelity-sweep}.test.ts→ 50/50 passed ✅npm run build→ success (ESM 1.72 MB) ✅session platforms→ all 6 platforms listed,codebuddy+codebuddy-ideboth✓ installed✅Fidelity: 100.0%, target id printed;claude --resume <id>picks it up with the session title ✅session rollback→ only the target copy removed, source session intact ✅sessions/repos/github.com_org_beta/andsessions/repos/gitlab.com_team_alpha/✅_unattributedwith an English warning ✅session list --all→ both projects listed with their SOURCE identity;session listfrom a project shows only that project's ✅session search <kw> --all→ hits sessions across two repo identities ✅xxx_1duplicate ✅session resumefrom the wrong project → English error namingsearch --all/--cwd, exit 1 ✅session pushinto a non-git repo root / no remote / concurrentindex.lock→ one-line English error + exit 1, no stack trace ✅npx vitest run→ failed files identical to the pre-change baseline (hook-handlers,dashboard-collector,recall-scope-isolation,contribute-self-learnings,push-team-config); none of them importsession-flow✅fidelity-sweep.test.tsroundtrips 5 platform routes and asserts message count/role/text/thinking/tool pairing/timestamps ✅Evidence: a real session relay — CodeBuddy IDE → claude-code (2661 messages / 47.5 MB)
The screenshots below are one continuous relay, all taken from the actual run. They live on the
session-migration-evidencebranch of this fork (kept out of the PR diff).Step 1 — the session lives in CodeBuddy IDE
Everyday work happens in the IDE. The migration does not require leaving it: the in-IDE agent provides and runs the exact commands, from enabling the new CLI to
migrate/rollback/--allvariants.Step 2 — run the migration
Fidelity: 100.0% (Mode A)andPreserved: 5816/5816 blocks.tool_not_in_targetwarnings are expected: this session used CodeBuddy-specific tools (team_create,send_message,ask_followup_question, …) with no same-named counterpart in claude-code. Their inputs and results are preserved as text blocks — readable after resume, but not replayable as tool calls.~/.claude/projects/-Users-...-teamai-cli/<uuid>.jsonl).Step 3 — resume in Claude Code: the relay completes
Claude Code's
/resumepicker, searched for "teamai cli": the migrated session appears under its original title ("完整的分析一下 seeeionflow ts版本的能力和 tea · 1 minute ago · 21.2 MB"). Selecting it continues the conversation with the full history visible — this is the relay completing. Before thetype:"summary"record fix, this picker showed a bare session id (824ff784).Same session, before and after
/resume)conversations[].nametype:"summary"recordNotes on the numbers:
extra/requestsmetadata; Claude records are flatter).tool_not_in_targetwarnings degrade CodeBuddy-only tools to text blocks: content preserved, tool structure not replayable.Notes for reviewers
origin/main(8ea0612) — rebased, CHANGELOG conflicts resolved by keeping both sides.--all, (3) the learnings loop.session save), so anything archived is team-readable. If that needs redaction or an opt-in gate, say so and I will add it before this lands.