Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
6661c6e
refactor(web): streamline sync, home, compression, and skills pages
ip2a Aug 6, 2026
879d461
chore: simplify gitignore and remove obsolete design docs
ip2a Aug 11, 2026
0fd1077
feat(providers): add Amazon Q, Qwen, and Kiro CLI session loading
ip2a Aug 11, 2026
e27ae50
feat(providers): broaden session discovery for Copilot and peers
ip2a Aug 11, 2026
5b840c1
refactor(rust): format CLI/core modules and tidy provider config helpers
ip2a Aug 11, 2026
932af7b
feat(web): centralize custom date range preferences in settings
ip2a Aug 11, 2026
d493b08
feat(web): redesign stats overview with charts and rankings
ip2a Aug 11, 2026
f726ebf
feat(web): embed stats, compression, and sync tabs in manager
ip2a Aug 11, 2026
c3b13c2
chore(web): align readiness checks and UI invariant coverage
ip2a Aug 11, 2026
9ccf813
feat(storage): add readiness_checkpoint table (schema v18)
ip2a Aug 11, 2026
cfbf43f
feat(readiness): signature-driven snapshot cache + decide_reconcile
ip2a Aug 11, 2026
6885670
feat(readiness): rewrite API layer for tiered reconcile
ip2a Aug 11, 2026
ab944e0
feat(web/readiness): backend-driven reconcile trigger, drop first-run…
ip2a Aug 11, 2026
00ef681
fix(tests): unblock pre-existing test breakage blocking readiness ver…
ip2a Aug 11, 2026
ec9c24a
feat(providers): emit native tool calls on codex/opencode export
ip2a Aug 11, 2026
4a223ad
fix(providers): correct codex/opencode export fidelity after native t…
ip2a Aug 11, 2026
89889f3
fix(providers): unify EventKind priority so ToolResult wins over Tool…
ip2a Aug 11, 2026
6c05f2c
feat(providers): opencode export Block::Patch as native patch part
ip2a Aug 11, 2026
9899edb
fix(providers): resolve clippy wildcard-in-or-pattern in codex export
ip2a Aug 11, 2026
8d4c55a
fix(providers): unify EventKind priority for pi/codebuddy/qoder/antig…
ip2a Aug 11, 2026
2672a49
fix(providers): correct import/export fidelity declarations for trae,…
ip2a Aug 11, 2026
cbc2185
fix(providers): declare import_fidelity for Augment (emerging.rs)
ip2a Aug 11, 2026
8df62e6
fix(providers): export_report reads fidelity.compressed for Block::Co…
ip2a Aug 11, 2026
2983ea0
feat(schema): explicit OASF schema name/version validation on session…
ip2a Aug 11, 2026
4ae45e0
test(providers): add interop fidelity guards for all providers
ip2a Aug 11, 2026
6e55854
docs: add provider matrix, OASF compatibility section, and CHANGELOG
ip2a Aug 11, 2026
3c00e76
fix(deepseek): item_json export preserves ToolCall/ToolResult structu…
ip2a Aug 11, 2026
fa30bdb
fix(deepseek): correct export_fidelity to Preserved for tool_call/too…
ip2a Aug 11, 2026
968e821
test(providers): add round-trip export-import tests for Claude and Codex
ip2a Aug 11, 2026
813b73c
fix(deepseek): content column excludes tool block text from multi-blo…
ip2a Aug 11, 2026
c6410b4
feat(web/skills): rename install to enable for skill install actions
ip2a Aug 11, 2026
27fdb6d
feat(skills): skip dot-prefixed entries in discovery
ip2a Aug 11, 2026
3e5186b
feat(skills): archive-based disable + re-enable + list-disabled
ip2a Aug 11, 2026
223901d
feat(skills): consolidate scattered copies + remove-symlinks
ip2a Aug 11, 2026
e7518eb
feat(web/skills): API + hooks for disable/enable/consolidate/remove-s…
ip2a Aug 11, 2026
a6d6c9b
feat(web/skills): disable / consolidate / remove-symlinks UI + disabl…
ip2a Aug 12, 2026
1a6b64c
test(web/skills): cover disable + remove-symlinks UI flows
ip2a Aug 12, 2026
27f10c7
feat(skills): add groups and scoped installation APIs
ip2a Aug 13, 2026
b36dfe2
feat(web/skills): scoped installations, groups UI, and consolidate panel
ip2a Aug 13, 2026
12f9f4f
feat(web): add path pickers and refresh settings/stats layout
ip2a Aug 13, 2026
b868b92
feat(web/skills): add group API hooks
ip2a Aug 19, 2026
14148c0
fix(codex): heal missing session index entries
ip2a Aug 19, 2026
0e63290
refactor(skills): simplify optional catalog lookup
ip2a Aug 19, 2026
e4d3b5c
fix(web/skills): retain selection after consolidation
ip2a Aug 19, 2026
a8626e0
feat: chain-of-thought header tags, bundled cursor CLI, install targets
ip2a Aug 21, 2026
49ef29d
fix(providers): drop stray archived default leaked into fn bodies
ip2a Aug 21, 2026
718fc87
feat(codex): mark rollouts under archived_sessions/ as archived
ip2a Aug 21, 2026
5a7d6d4
feat(deepseek): surface sqlite archived flag in summaries
ip2a Aug 21, 2026
02b35f8
feat(hermes): surface sqlite archived flag in summaries
ip2a Aug 21, 2026
1695075
feat(opencode): surface time_archived as archived
ip2a Aug 21, 2026
a54619e
feat(kimi): surface state.json archived flag
ip2a Aug 21, 2026
e5cc09e
feat(cursor): surface composerHeaders.isArchived as archived
ip2a Aug 21, 2026
c9c7d4a
feat(storage): persist and project provider archived flag
ip2a Aug 21, 2026
e291cea
feat(web): show archived badge on sessions
ip2a Aug 21, 2026
e302c03
feat: add session list filters
ip2a Aug 21, 2026
6998e79
feat: simplify CLI command surface
ip2a Aug 21, 2026
d1776a5
fix(tests): align DeepSeek export fidelity assertion
ip2a Aug 21, 2026
563f44e
fix(core): skip missing sources during text search
ip2a Aug 21, 2026
d0102a6
test(cli): remove obsolete compression command test
ip2a Aug 21, 2026
7633eb5
fix(cli): honor global json for interactive interfaces
ip2a Aug 21, 2026
4999148
docs(cli): make help agent-friendly
ip2a Aug 21, 2026
41ca06c
docs: consolidate CLI reference and normalize formatting
ip2a Aug 26, 2026
8d18c14
feat(skills): add management module with write-side lifecycle operations
ip2a Aug 26, 2026
a5b42e3
refactor(cli): delegate skills mutations to memorph management module
ip2a Aug 26, 2026
7904e7d
refactor(web): add bordered variant to dialog header/footer and norma…
ip2a Aug 28, 2026
513fb3c
fix(ignore): unblock rust/apps traversal and provider fixture whitelist
ip2a Aug 28, 2026
e7378a3
feat(release): orchestrate tag publishing via single dispatch workflow
ip2a Aug 28, 2026
060098d
fix(web): resolve type errors and refresh stale skill tests
ip2a Aug 28, 2026
c04fd8f
refactor(web): grey full-bleed canvas with floating card surfaces
ip2a Aug 28, 2026
3f4f3d1
refactor(web): add panel variant to dialog content and adopt it
ip2a Aug 28, 2026
c6dff16
merge: feature/web-style-migration into develop
ip2a Aug 28, 2026
b24a8fe
chore(desktop): bump oasf lock to 0.2.0 from crates.io
ip2a Sep 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .github/workflows/release-orchestrate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: release-orchestrate

# One command publishes everything for tag vX.Y.Z:
# gh workflow run release-orchestrate.yml --ref vX.Y.Z -f version=X.Y.Z
# Resolves the release-build run for the tag, then serially dispatches:
# crates -> npm -> pypi -> latest-json -> post-release-verify
# Each child keeps its own context validation; this workflow only sequences them.

on:
workflow_dispatch:
inputs:
version:
description: "Version without leading v (must match tag vX.Y.Z and Cargo.toml)"
required: true
type: string

permissions:
contents: read
actions: write

concurrency:
group: release-orchestrate-${{ inputs.version }}
cancel-in-progress: false

jobs:
orchestrate:
name: orchestrate release v${{ inputs.version }}
runs-on: ubuntu-latest
timeout-minutes: 60
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ inputs.version }}
steps:
- name: Checkout release tag
uses: actions/checkout@v4

- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Validate release context
run: python3 scripts/validate_release_context.py

- name: Resolve release-build run
run: |
TAG="v$VERSION"
RUN_JSON=$(gh run list --workflow=release-build.yml --branch "$TAG" --event push --json databaseId,status,conclusion,headSha --limit 1)
echo "$RUN_JSON"
RUN_ID=$(echo "$RUN_JSON" | jq -r '.[0].databaseId // empty')
STATUS=$(echo "$RUN_JSON" | jq -r '.[0].status // empty')
CONCLUSION=$(echo "$RUN_JSON" | jq -r '.[0].conclusion // empty')
HEAD_SHA=$(echo "$RUN_JSON" | jq -r '.[0].headSha // empty')
[ -n "$RUN_ID" ] || { echo "::error::No release-build run found for tag $TAG"; exit 1; }
[ "$STATUS" = "completed" ] || { echo "::error::release-build run $RUN_ID is still $STATUS"; exit 1; }
[ "$CONCLUSION" = "success" ] || { echo "::error::release-build run $RUN_ID concluded: $CONCLUSION"; exit 1; }
[ "$HEAD_SHA" = "$GITHUB_SHA" ] || { echo "::error::release-build headSha $HEAD_SHA != checkout $GITHUB_SHA"; exit 1; }
echo "BUILD_RUN_ID=$RUN_ID" >> "$GITHUB_ENV"

- name: Publish (crates → npm → pypi → latest-json → verify)
run: |
TAG="v$VERSION"
dispatch_and_wait() {
local workflow="$1"; shift
echo "=== dispatching $workflow ==="
gh workflow run "$workflow" --ref "$TAG" "$@"
sleep 10
local run_id=""
for _ in 1 2 3 4 5 6; do
run_id=$(gh run list --workflow="$workflow" --branch "$TAG" --event workflow_dispatch --json databaseId,status \
--jq '[.[] | select(.status != "completed")][0].databaseId // empty')
[ -n "$run_id" ] && break
sleep 10
done
[ -n "$run_id" ] || { echo "::error::$workflow run not found after dispatch"; exit 1; }
gh run watch "$run_id" --exit-status
}
dispatch_and_wait release-publish-crates.yml
dispatch_and_wait release-publish-npm.yml -f build_run_id="$BUILD_RUN_ID"
dispatch_and_wait release-publish-pypi.yml -f build_run_id="$BUILD_RUN_ID"
dispatch_and_wait release-update-latest-json.yml -f version="$VERSION"
dispatch_and_wait post-release-verify.yml -f version="$VERSION"

- name: Release summary
run: |
gh release view "v$VERSION" --json tagName,isDraft,assets --jq '{tag: .tagName, draft: .isDraft, assets: (.assets | length)}'
28 changes: 5 additions & 23 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
*

# Keep directory traversal so whitelisted paths below can be reached.
!*/

# Always ignore local-only directories and artifacts.
/.claude/
Expand All @@ -21,6 +20,7 @@
/desktop/tauri/gen/
/desktop/tauri/target/
**/__pycache__/
local/*

# Root project metadata.
!/.gitignore
Expand All @@ -33,15 +33,18 @@

# Rust workspace.
!/rust/
!/rust/crates/**/
!/rust/Cargo.toml
!/rust/Cargo.lock
!/rust/crates/
!/rust/crates/**/Cargo.toml
!/rust/crates/**/*.rs
!/rust/crates/**/CHANGELOG.md
!/rust/crates/**/assets/
!/rust/crates/**/assets/*.json
/rust/crates/**/assets/web/
!/rust/apps/
!/rust/apps/**/
!/rust/apps/**/Cargo.toml
!/rust/apps/**/*.rs
!/rust/apps/**/assets/
Expand All @@ -53,13 +56,6 @@
!/.github/workflows/
!/.github/workflows/*.yml

# Local draft documentation.
/docs/*
# 规范文档作为架构验收标准,纳入版本控制
!/docs/架构文档-重要架构设计v1.md
!/docs/项目骨架设计v1.md
!/docs/重构计划-v1.md
!/docs/技术文档-LIB说明v1.md

# Web app source.
!/apps/
Expand Down Expand Up @@ -109,20 +105,6 @@
!/python/packages/memorph/src/memorph/
!/python/packages/memorph/src/memorph/*.py

# Research notes (not part of the project source).
/headroom的调研报告.md
/memorph基于headroom完善压缩机制。md

# Provider-native test fixtures.
!/rust/crates/memorph/src/providers/kimi/fixtures/
!/rust/crates/memorph/src/providers/kimi/fixtures/**
!/rust/crates/memorph/src/providers/kiro/fixtures/
!/rust/crates/memorph/src/providers/kiro/fixtures/**
!/rust/crates/memorph/src/providers/cursor/fixtures/
!/rust/crates/memorph/src/providers/cursor/fixtures/**

# Project-wide Codex experience instructions.
!AGENTS.md
!.agent/
!.agent/config.toml
!docs/codex-experience.md
!/rust/crates/memorph/src/providers/**/fixtures/**
183 changes: 85 additions & 98 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,151 +88,138 @@ npx memorph

### CLI

CLI模式更多的是结合`SKILLS`之后利用agent帮你管理会话的迁移与管理
CLI 可用于脚本、Agent 和人工操作。无参数运行直接打开 TUI;所有命令支持全局 `--json`。

#### 查看当前工作区的可用会话-list
#### 会话列表与过滤:list

```bash
memorph list [OPTIONS]
```

| 参数 | 说明 |
|------|------|
| `--all` | 显示所有工作区的会话 |
| `--claude` | 仅显示 Claude Code 会话 |
| `--codex` | 仅显示 Codex 会话 |
| `--opencode` | 仅显示 OpenCode 会话 |
| `--all` | 显示所有工作区会话 |
| `-p, --provider <PROVIDER>` | 限定 Provider,可重复 |
| `--sort <recent/title>` | 排序方式 |
| `--limit <N>` / `--offset <N>` | 分页 |
| `-d, --dir <DIR>` | 匹配项目目录或源路径 |
| `-s, --session <PATTERN>` | 匹配会话 ID 或标题 |
| `--title <PATTERN>` | 匹配会话标题 |
| `--text <PATTERN>` | 搜索消息正文 |
| `--since <TIME>` / `--before <TIME>` | 时间过滤:日期、RFC3339、`7d`、`24h`、`30m` |
| `--min-bytes <BYTES>` / `--max-bytes <BYTES>` | 大小过滤:字节、`K`、`M`、`G` |
| `--providers` | 显示 Provider 能力矩阵 |
| `--json` | 输出 JSON,可放在命令前或命令后 |

##### 示例
```bash
$ memorph list
memorph list
memorph list --all --title "登录" --since 7d
memorph --json list --text "错误" | jq .
memorph list --providers --provider codex
```
![列出会话](assets/zh/show-list.png)

![列出会话](assets/zh/show-list.png)

#### 将指定会话迁移-switch
#### 会话迁移:switch

```bash
memorph switch --<from>2<to> [OPTIONS]
memorph switch <FROM> <TO> [OPTIONS]
memorph migrate <FROM> <TO> [OPTIONS] # switch 别名
```

| 参数 | 说明 |
|------|------|
| `--claude2codex` | Claude → Codex |
| `--codex2claude` | Codex → Claude |
| `--claude2opencode` | Claude → OpenCode |
| `--opencode2claude` | OpenCode → Claude |
| `--codex2opencode` | Codex → OpenCode |
| `--opencode2codex` | OpenCode → Codex |
| `-s, --session-id <ID>` | 源会话 ID,**省略则取当前工作区最近会话** |
| `-d, --to-dir <DIR>` | 目标目录,**默认:当前目录** |

| `FROM` / `TO` | 源 Provider / 目标 Provider |
| `-s, --session-id <ID>` | 源会话 ID;省略则使用当前工作区最近会话 |
| `-t, --to-dir <DIR>` | 目标项目目录 |

##### 示例
```bash
$ memorph switch --claude2codex --session-id abc-123-session-id
memorph switch claude codex --session-id abc-123-session-id
memorph migrate claude codex --session-id abc-123-session-id
```

![迁移会话](assets/zh/show-list.png)

---

#### CLI 表格
#### CLI 命令

| 命令 | 说明 |
|------|------|
| [`list`](#查看当前工作区的可用会话-list) | 列出会话(默认仅当前工作区) |
| [`export`](#export) | 导出会话为 `.json` / `.md` / `.html` 文件 |
| [`import`](#import) | 将 `.json` / `.md` / `.html` 文件或已有会话导入目标工具 |
| [`remove`](#remove--rename--find) | 删除指定会话 |
| [`rename`](#remove--rename--find) | 重命名指定会话 |
| [`switch`](#将指定会话迁移-switch) | 跨 Provider 迁移会话 |
| [`find`](#remove--rename--find) | 按目录、标题或 ID 搜索会话 |


---
| `list` | 列出并过滤会话,或显示 Provider 能力 |
| `switch` / `migrate` | 跨 Provider 迁移会话 |
| `export` | 导出会话 |
| `import` | 导入会话 |
| `remove` | 删除会话 |
| `rename` | 重命名会话 |
| `web` / `api` / `tui` | 启动 Web、API 或 TUI |
| `doctor` | 输出只读环境诊断 |
| `update` | 按安装来源更新 memorph |

#### 导入与导出

##### 导出

```bash
memorph export <PROVIDER> <SESSION_ID> [OPTIONS]
memorph export <PROVIDER> <SESSION_ID> [-o PREFIX] [-f FORMAT]
memorph import <PROVIDER> <FILE_OR_ID> [-t DIR]
```

| 参数 | 说明 |
|------|------|
| `PROVIDER` | 目标 Agent:`claude` / `codex` / `opencode` |
| `SESSION_ID` | 会话 ID |
| `-o, --output <PREFIX>` | 输出文件名前缀,**默认:`SESSION_ID`** |
| `-f, --format <FORMAT>` | `json` / `md` / `html`,**默认:`json`** |

```bash
memorph export claude abc-123-session-id
memorph export claude abc-123-session-id -f md
```

##### 导入

```bash
memorph import <PROVIDER> <FILE_OR_ID> [OPTIONS]
```

| 参数 | 说明 |
|------|------|
| `PROVIDER` | 目标 Agent:`claude` / `codex` / `opencode` |
| `FILE_OR_ID` | `.json`/`.md`/`.html` 文件路径,或已有会话 ID |
| `-d, --to-dir <DIR>` | 目标项目目录,**默认:当前目录** |

```bash
memorph import codex ./my-session.md
memorph import claude ./backup.json --to-dir ~/projects/my-app
memorph import claude xyz-456-session-id
```

---

#### 删除与重命名

| 命令 | 语法 | 说明 |
|------|------|------|
| `remove` | `memorph remove <PROVIDER> <SESSION_ID>` | 删除会话 |
| `rename` | `memorph rename <PROVIDER> <SESSION_ID> <NEW_TITLE>` | 重命名会话 |

```bash
# 删除
memorph remove claude abc-123-session-id

# 重命名
memorph rename claude abc-123-session-id "修复登录 bug"
memorph remove <PROVIDER> <SESSION_ID>
memorph rename <PROVIDER> <SESSION_ID> <NEW_TITLE>
```

---

#### 查询

```bash
memorph find [OPTIONS]
memorph remove claude abc-123-session-id
memorph rename claude abc-123-session-id "修复登录 bug"
```

| 参数 | 说明 |
|------|------|
| `-d, --dir <DIR>` | 按项目目录路径模糊搜索 |
| `-s, --session <PATTERN>` | 按会话 ID 或标题模糊匹配 |
| `-p, --provider <PROVIDER>` | 限制 Provider(可多次使用) |

**查询约束:** 至少需提供 `--dir`、`--session`、`--provider` 中的一个。

```bash
# 按目录搜索
memorph find --dir ~/projects/my-app

# 按标题或 ID 搜索
memorph find --session "登录 bug"

# 只在 Claude 和 Codex 中搜索
memorph find --session "refactor" -p claude -p codex
```
### Provider 支持矩阵

memorph 支持 23 个 AI 编程 Agent 的会话管理。各 Provider 的能力存在差异:

| Provider | 导入 | 导出 | 管理/恢复 |
|---|---:|---:|---:|
| Claude | ✅ | ✅ | ✅ |
| Codex | ✅ | ✅ | ✅ |
| OpenCode | ✅ | ✅ | ✅ |
| DeepSeek | ✅ | ✅ | ✅ |
| Kimi | ✅ | ✅ | ✅ |
| Cursor | ✅ | ✅ | ✅ |
| Gemini CLI | ✅ | ❌ | ✅ |
| Kiro | ✅ | ❌ | ✅ |
| Hermes | ✅ | ❌ | ✅ |
| Cline | ✅ | ❌ | ❌ |
| Copilot | ✅ | ❌ | ❌ |
| Droid | ✅ | ❌ | ❌ |
| CodeBuddy | ✅ | ❌ | ❌ |
| Qoder | ✅ | ❌ | ❌ |
| Trae | ✅ | ❌ | ❌ |
| WorkBuddy | ✅ | ❌ | ❌ |
| Pi | ✅ | ❌ | ❌ |
| Antigravity | ✅ | ❌ | ❌ |
| OpenClaw | ✅ | ❌ | ❌ |
| Augment | ✅ | ❌ | ❌ |
| Windsurf | ✅ | ❌ | ❌ |
| Amazon Q | ✅ | ❌ | ❌ |
| Qwen | ✅ | ❌ | ❌ |

> **导出**:将 OASF canonical Session 回写为 Provider 原生格式。
> **管理/恢复**:支持 delete / rename / resume 中至少一项。
> 导入侧使用统一的 OASF Session 模型,导出侧的保真度取决于目标 Provider 的原生格式能力。

### OASF 兼容性

memorph 基于 [OASF (Open Agent Session Format)](https://crates.io/crates/oasf) v2(crate `oasf` 0.2.0)构建。

- 所有会话文件(`.morph`、`.json`、`.md`、`.html`)在 meta 行携带 schema name/version,导入时校验,拒绝不兼容版本
- 导入侧:23 个 Provider 的原生格式统一转换为 OASF canonical Session
- 导出侧:6 个 Provider 支持将 canonical Session 回写为原生格式(Claude、Codex、OpenCode、DeepSeek、Kimi、Cursor)
- 保真度模型:每个 Provider × Block 类型声明 `Preserved` / `Normalized` / `Downgraded` / `Dropped` / `Unsupported`,通过 `export_report` 在导出时生成损失报告

---

Expand Down
Loading
Loading