DeepSeek Harness plugin

dsh-session-import

Cross-tool session migration for DeepSeek Harness: ingest, continue, knowledge extraction, bidirectional export, and privacy redaction.

Jump to install

Source facts

Repository
devmom/dsh-session-import
Latest update
Aug 14, 2026
Category
Tools & Capabilities
GitHub stars
1
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/devmom/dsh-session-import
Plugin: dsh-session-import
Author: devmom

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer4 files
README.en.mdSource · read only
README language

session-import

中文 · English

Cross-tool session migration plugin for the DeepSeek Harness (dsh) — a real dsh bundle plugin:

  • 15+ source session import (ChatGPT / Claude Code / Codex / Kimi Code / ZCode / WorkBuddy / OpenClaw / Gemini / Cursor / Aider / Continue / Cline / OpenCode / Reasonix / GitHub Copilot Chat / generic JSON);
  • Imports produce native dsh session-log events (turn/start · user/message · assistant/message (with thinking reasoning blocks and tool-call blocks) · tool/call · tool/result · turn/end), written via ctx.sessions and persisted to the official JSONL backend — imported sessions render natively in the dsh Web UI and can be continued;
  • Bidirectional export (dsh session → generic JSON / Markdown / transcript);
  • Privacy redaction detection (API Key / phone / email / ID card / IP / bank card);
  • Knowledge extraction (decisions / code / conventions → deduplicated local memory, via the memory seam).

Design docs: see [docs/](docs/) — [PRD](docs/PRD-session-import.md) · [ARCH](docs/ARCH-session-import.md) · [TECH](docs/TECH-session-import.md).

Implemented (mapped to FR/NFR/AC)

ModuleFileRequirements
Pluggable parser adapters (14+ sources)src/parsers/*.tsFR-01/02/03/16
Adapter registry + detectionsrc/registry.tsFR-02 — detect() sniffing + generic fallback
Real dsh session-event mappingsrc/mapping.tsFR-04/05/06 — native Session.append vocabulary (turn/user/assistant/tool), thinking→reasoning blocks, unknown tools→tool/result.meta.unknownTool
Privacy redactionsrc/privacy.tsFR-15/AC-3
Bidirectional export (event inversion)src/exporter.tsFR-13
Knowledge extractionsrc/knowledge.ts, src/heuristicJudge.tsFR-11/12
Import orchestrationsrc/importService.tsFR-07/08/09/14/15/16 — conflict rename/merge/skip, archive, robust SkipError
Streaming chunked importsrc/streamImport.tsFR-10/NFR-02
Real dsh seam adapterssrc/dsh/dshRuntime.tsctx.sessions / ctx.sessionTitle / ctx.credentials; archives/history/memory under $DSH_HOME/session-import
Cordis plugin entrysrc/plugin.tsapply(ctx, config): sessionImport service, /session-import command, /api/session-import/* REST routes
Bundle manifestcordis.patch.yml, package.json#dsh.bundleStandard dsh profile bundle protocol
Standalone dev wizard (optional)src/server.ts, public/*Local wizard without the harness (npm run wizard)

Install into dsh

Option A: from the npm registry (simplest)

# pnpm 9.x needs the -w flag for workspace-root installs (dsh plugin forwards pnpm args verbatim)
dsh plugin --profile web add -w session-import

# dsh auto-adds the package to the profile's dsh.profile.bundles (it detects the
# dsh.bundle declaration); restart dsh to activate

Option B: local development / not yet published (link to the plugin dir)

# Build once in the plugin directory (produces dist/ and lib/)
npm install && npm run build && npm run bundle:client

# Install into your profile (web example)
dsh plugin --profile web add -w link:D:/work/DeepSeekHarness/Plugins/session-import
# or manually: add "session-import": "link:<absolute-path>" to profile/package.json
# dependencies and append "session-import" to dsh.profile.bundles, then pnpm install there

# Restart dsh, then:
#   - Web UI: /session-import <export-file-path> [--redact] [--extract-knowledge]
#   - or REST: POST /api/session-import/import

> Windows note: pnpm 9.x has a known issue resolving file:D:/... absolute paths (it > mangles the drive letter into the profile dir). Use the link:<absolute-path> > specifier for local development (pnpm creates a junction). Registry installs are unaffected.

Publishing to npm (maintainers)

npm login                                   # any npm account (session-import is unscoped)
npm version patch|minor|major               # bump version
npm publish                                 # prepublishOnly runs build:all + test automatically

Usage surfaces inside dsh

0. Web import wizard (multi-select checkboxes, browser UI plugin) — open any session → top Tab "Import": - Full candidate list: auto-scans all registered sources (Codex / Claude Code / …), showing title/messages/size/age per row; - Multi-select: checkboxes + select-all/clear, then import the confirmed files as individual dsh sessions; - Title option: tick "derive titles from first message" so unnamed Codex sessions get a title from the first user message (approximates Codex auto-naming / desktop preview); unticked uses the timestamp title; - Import results shown inline (session ids / skip reasons), list auto-refreshes (sidebar too). - Data path: the browser talks to /api/session-import/scan-dir and /api/session-import/import-paths on the host webserver. 1. Conversational discovery/import (model tools) — the agent drives "scan → confirm → import": - chat_import_discover: probes the well-known local session dirs (see the table below), returns a numbered candidate list (title/path/messages/size/age), read-only; supports titleFromFirstMessage. - chat_import_import: imports the user-confirmed paths as new dsh sessions (supports redact / extractKnowledge / titleFromFirstMessage); failed files are skipped with reasons; titles come from the source (Codex thread names / Claude Code ai-title), unnamed ones fall back to a readable timestamp or the first user message when titleFromFirstMessage is set. - Example: > User: import my recent Codex sessions > Agent: chat_import_discover → list candidates → User: import 1、3、5 → Agent: chat_import_import → summary - On by default; disable with bundle config enableModelTools: false. 2. /session-import slash command (Web UI / any commands adapter): `` /session-import C:\path\to\chatgpt\conversations.json # single file /session-import C:\Users\PC\.codex\sessions # directory (recursive scan) /session-import C:\Users\PC\.codex\sessions --source codex # codex only /session-import <path> --redact --extract-knowledge # redact + knowledge extraction ` Directory imports return a summary (imported 21/21 session(s) (codex×21)); bad files are skipped without aborting (FR-16). 3. sessionImport service (other plugins / scripts): `ts const svc = ctx.get('sessionImport') // { ingest, sources, detectSource, parseCount, scanDirectory, ingestDirectory } const preview = await svc.scanDirectory('C:/Users/PC/.codex/sessions', { sourceFilter: ['codex'] }) const batch = await svc.ingestDirectory('C:/Users/PC/.codex/sessions', { sourceFilter: ['codex'], redact: true }) // batch: { dir, total, imported: ImportResult[], skipped: {path,reason}[], ignored: number } ` 4. REST API (web profile, registered on the host webserver): - GET /api/session-import/adapters — registered source ids - POST /api/session-import/import{ fileName, text, options } single-file import - POST /api/session-import/scan-dir{ sourceFilter?, maxFiles?, titleFromFirstMessage? } discovery scan (returns numbered candidate groups with titles, no writes) - POST /api/session-import/import-dir{ dir, options, sourceFilter?, maxFiles? } batch directory import - POST /api/session-import/import-paths{ paths, options } import confirmed paths (wizard/conversation shared) - GET /api/session-import/history — import history 5. Data landing: sessions → official dsh session-log ($DSH_HOME/sessions, JSONL, grouped by workspace bound to the source cwd); original archives / import history / local memory → $DSH_HOME/session-import/ (override with bundle config dataDir`).

Source adapter coverage (mainstream agent frameworks)

Frameworksource idAuto-discovery dir (env override)ParserStatus
Codex CLIcodex~/.codex/sessions (CODEX_HOME)Dedicated (rollout + legacy; title chain: session_index.jsonl thread name → optional first-user-message → timestamp fallback; session_meta.cwd binding)✅ verified against real sessions
Claude Codeclaude_code~/.claude/projects (CLAUDE_CONFIG_DIR)Dedicated (session-based + legacy; ai-title title, cwd binding)✅ verified against real sessions
Kimi Codekimi_code~/.kimi-code/sessions (KIMI_CODE_HOME)Dedicated v2 (real wire.jsonl event stream: turn.prompt/context.append_loop_event (content.part think/text, tool.call/tool.result); state.json title + session_index.jsonl workdir; sub-agents agents/agent-N too)✅ verified against real sessions
ZCode (Zhipu GLM)zcode~/.zcode/cli (ZCODE_HOME)Dedicated v2 (both real formats: sub-agent transcript.jsonl (turn_started/model_streaming/tool_call_scheduled/turn_complete) + main-session rollout/model-io-sess_*.jsonl (model_io snapshots with reasoning/toolCalls, system-reminder/task-notification noise filtered); metadata.json → title description + cwd binding)✅ verified against real sessions (main 32 msgs + sub-agent)
WorkBuddy / CodeBuddy (Tencent)workbuddy~/.codebuddy (CODEBUDDY_HOME)OpenAI message format / generic JSON (exported sessions)✅ synthetic import verified (no local sessions)
OpenClaw (claw.so)openclaw~/.openclaw/agents (OPENCLAW_HOME)Dedicated (real session log: session (cwd binding) / message (text / thinking / toolCall / toolResult blocks))✅ verified against real sessions
Gemini CLIgemini~/.gemini (GEMINI_HOME)Dedicated (chats.history)✅ synthetic import verified (not installed)
Cursorcursor~/.cursor (CURSOR_HOME)Dedicated (source:cursor/toolCalls)✅ synthetic import verified (not installed)
Aideraider~/.aider (AIDER_HOME)Dedicated (markdown history)✅ synthetic import verified (not installed)
Continuecontinue~/.continue/history (CONTINUE_HOME)OpenAI message format (files detect as openai_family)✅ synthetic import verified (not installed)
OpenCodeopencode~/.opencode/sessions (OPENCODE_HOME)OpenAI message format (files detect as openai_family)✅ synthetic import verified (not installed)
Cline / Copilot Chat exportsopenai_familycustom CHAT_IMPORT_OPENAI_DIROpenAI message format✅ synthetic import verified
ChatGPTchatgptmanual export fileDedicated (mapping graph)✅ unit-test covered
Any JSONgeneric_jsonmanual filegeneric fallback

> Each framework joins auto-discovery with one row in AGENT_SOURCES (src/discovery.ts); > SQLite-backed frameworks (new Cline/Continue, Trae, 通义灵码, DevChat, …) integrate via exported JSON; local sqlite parsing is future work. > chat_import_discover / the wizard only list directories that actually exist on the machine. > Verification: node scripts/verify-all-sources.mjs — detect → parse → import for every registered framework (real sessions when present: codex / claude_code / kimi_code / zcode / openclaw; synthetic fixtures otherwise: gemini / cursor / aider / continue / opencode / openai_family / workbuddy).

Development without the harness (headless / standalone wizard)

npm test            # 89 cases (node --import tsx --test)
npm run build       # tsc strict → dist/
npm run wizard      # standalone import wizard http://localhost:4173 (pure local-file seams)

E2E scripts (real dsh profile):

  • node scripts/verify-dsh.mjs — service/command/import/persistence assertions
  • node scripts/verify-all-sources.mjs — detect → parse → import for all registered frameworks (real/synthetic)
  • node scripts/verify-zcode.mjs — ZCode main rollout + sub-agent real import (title/cwd persistence)
  • node scripts/verify-install.mjs — tarball-install usability check (npm packdsh plugin add into a temp DSH_HOME → boot → import, self-contained)
  • node scripts/demo-codex.mjs <rollout.jsonl> — import one real Codex session
  • node scripts/demo-scan.mjs <dir> [--import] [--source codex] [--redact] [--limit N] — directory scan/batch import demo
  • node scripts/demo-discover.mjs [--import-limit N] — model-tool loop: discover real candidates → import → persistence check

> These scripts boot a real dsh installation (dsh-app-boot). The dsh checkout path is > resolved by scripts/lib/dsh-env.mjs: $DSH_CHECKOUT env > dsh CLI on PATH > npm global root. > No script edits needed — install dsh on PATH or set DSH_CHECKOUT to run on another machine.

CI (GitHub Actions, .github/workflows/ci.yml): on push/PR runs Node 18/20/22 matrix of typecheck → build → client bundle → unit tests → npm pack content check, plus a dsh-integration job (installs the dsh CLI, runs verify-dsh + verify-all-sources synthetic fixtures).

Minimal usage (no harness):

import { buildHeadlessContainer } from './dist/plugin.js';
import { HeuristicLlmJudge } from './dist/heuristicJudge.js';
const { service } = buildHeadlessContainer(new HeuristicLlmJudge());
const result = await service.ingest(
  { path: 'codex-session.jsonl', text: '<Codex transcript JSONL>' },
  { redact: true, extractKnowledge: true },
);
console.log(result.sessionId, result.messageCount);

End-to-end verification (real dsh)

scripts/verify-dsh.mjs boots a profile containing this plugin exactly like the dsh CLI does, and asserts: sessionImport service available, /session-import command registered, imports produce real session events, and JSONL persistence succeeds:

node scripts/verify-dsh.mjs        # needs $DSH_HOME/profiles/ci-chat-headless (installed as above)

Uninstall

dsh plugin --profile web remove session-import
# or remove the dependency and bundles entry from the profile package.json, then restart the harness
# Historical data: deleting $DSH_HOME/session-import clears archives/history/memory; sessions remain in the dsh session store

Adding a new source adapter

import { ParserAdapter, RawInput, msg } from './src/parsers/base.js';
export class MyToolAdapter implements ParserAdapter {
  readonly source = 'mytool';
  readonly schemaVersion = '1.0';
  detect(raw: RawInput) { /* sniff distinctive features, avoid false positives */ return false; }
  parse(raw: RawInput) { return { source: this.source, messages: [] }; }
}
// register(new MyToolAdapter()) in createDefaultRegistry() (src/registry.ts), specific sources first

Known boundaries

  • Knowledge extraction defaults to the offline heuristic HeuristicLlmJudge (enabled with defaultExtractKnowledge: true); wiring a real LLM channel (ctx.llm) is future work.
  • Imported sessions are named import-<uuid> to avoid collisions with the store's per-process counter ids and existing on-disk logs.
  • Sessions bind to the source working directory: Codex rollout session_meta.cwd is written into the imported session's SessionHeader.cwd — the session lands in the matching workspace (sidebar group) and satisfies dsh's hard cwd requirement for cold resume / model selection (sessions without cwd cannot resume).
  • Session titles: Codex thread names come from ~/.codex/session_index.jsonl (thread_name) and are applied automatically on import (session/title, user source pinned, never overwritten by fallbacks); unnamed sessions get dsh's first-message fallback.
  • dsh currently has no memory-service seam, so knowledge sinks to plugin-local files; ICredentials is wired to the real ctx.credentials.