Skip to content

Commit c53b2b6

Browse files
Myoontyeeclaude
andcommitted
v0.8.11: fix P1 — export Codex sessions to cwd-based .codex-history/
Each session now exports to <session.cwd>/.codex-history/ instead of the active VS Code workspace root. Sessions from 3decoder-experiments will land in 3decoder-experiments/.codex-history/, collective-intelligence sessions in collective-intelligence/.codex-history/, etc. Falls back to workspaceRoot if cwd doesn't exist on disk. Also fix buildFilename() to use codexSessionTitle() (which honours threadName) instead of the old raw-message extraction that grabbed system-injected text. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4eb224d commit c53b2b6

File tree

3 files changed

+127
-16
lines changed

3 files changed

+127
-16
lines changed

CLAUDE.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# claude-code-exporter — 开发规范
2+
3+
## 机器架构(必须搞清楚再动手)
4+
5+
```
6+
本地主机 (你的电脑)
7+
├── Claude Code Exporter 源码 e:/001Code/Jupyter/Claude-Code-Tools/claude-code-exporter/
8+
├── 编译 / 打包 / git push 在这里做
9+
└── SCP 把 .vsix 传给 4090
10+
11+
4090 服务器 (Ph.D.Chen@4090-server)
12+
├── Codex APP 产生 JSONL → C:/Users/Ph.D.Chen/.codex/sessions/
13+
├── session_index.jsonl → C:/Users/Ph.D.Chen/.codex/session_index.jsonl
14+
├── Cursor 加载插件 → C:/Users/Ph.D.Chen/.cursor/extensions/
15+
└── 导出落地目录 → <workspace>/.codex-history/
16+
```
17+
18+
**插件在 4090 的 Cursor 里运行,读的是 4090 的文件系统。**
19+
在本地确认代码逻辑后,所有验证必须在 4090 上做,不是在本地。
20+
21+
---
22+
23+
## 强制验证脚手架 — 每次改动后必须跑完
24+
25+
改动代码 → 编译 → 打包 → 安装 → **验证** 这五步缺一不可。
26+
**没跑完验证就说"修好了"是放屁。**
27+
28+
### Step 1: 编译 & 打包(本地)
29+
30+
```bash
31+
cd e:/001Code/Jupyter/Claude-Code-Tools/claude-code-exporter
32+
npm run build 2>&1 # 必须无 error
33+
npm run package 2>&1 # 确认 .vsix 生成
34+
```
35+
36+
### Step 2: 传到 4090 并安装(本地执行)
37+
38+
```bash
39+
VERSION=$(node -p "require('./package.json').version")
40+
VSIX="claude-code-exporter-${VERSION}.vsix"
41+
42+
scp -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
43+
"$VSIX" "Ph.D.Chen@4090-server:C:/Users/Ph.D.Chen/Downloads/$VSIX"
44+
45+
# 生成并执行安装脚本
46+
cat > /tmp/install_cce.ps1 << EOF
47+
\$version = "${VERSION}"
48+
\$vsix = "C:\Users\Ph.D.Chen\Downloads\claude-code-exporter-\${version}.vsix"
49+
\$zip = \$vsix -replace '\.vsix$', '.zip'
50+
\$tmp = "C:\Users\Ph.D.Chen\Downloads\ext-extract-cce-\${version}"
51+
\$extDir = "C:\Users\Ph.D.Chen\.cursor\extensions\myoontyee.claude-code-exporter-\${version}"
52+
53+
Copy-Item \$vsix \$zip -Force
54+
if (Test-Path \$tmp) { Remove-Item \$tmp -Recurse -Force }
55+
Expand-Archive -Force -Path \$zip -DestinationPath \$tmp
56+
New-Item -ItemType Directory -Force -Path \$extDir | Out-Null
57+
Get-ChildItem "\$tmp\extension" | ForEach-Object { Copy-Item -Recurse -Force \$_.FullName \$extDir }
58+
Write-Host "Installed: \$extDir"
59+
EOF
60+
61+
scp -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
62+
/tmp/install_cce.ps1 "Ph.D.Chen@4090-server:C:/Users/Ph.D.Chen/install_cce.ps1"
63+
64+
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
65+
"Ph.D.Chen@4090-server" "powershell -NoProfile -File C:/Users/Ph.D.Chen/install_cce.ps1"
66+
```
67+
68+
### Step 3: 验证 session_index 可读(4090)
69+
70+
```bash
71+
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
72+
"Ph.D.Chen@4090-server" \
73+
"powershell -Command \"Get-Content 'C:\Users\Ph.D.Chen\.codex\session_index.jsonl' | Select-Object -First 5\""
74+
```
75+
76+
期望:能看到含 `thread_name` 的 JSON 行。如果文件不存在或为空,标题修复根本不会生效,不要继续。
77+
78+
### Step 4: 验证导出文件名(4090 上手动操作 + SSH 确认)
79+
80+
**4090 上操作:**
81+
1. 重启 4090 的 Cursor(不是 Codex APP,是 Cursor)
82+
2. 打开 Claude Code Exporter 的 Sessions 面板
83+
3. 找到目标 Codex 会话,点 Export 按钮(re-export 会覆盖旧文件名)
84+
85+
**SSH 确认结果:**
86+
```bash
87+
# 替换为实际 workspace 路径
88+
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
89+
"Ph.D.Chen@4090-server" \
90+
"powershell -Command \"Get-ChildItem 'E:\001Code\Jupyter\000PhD\I_CT\3decoder-experiments\.codex-history' -Filter '*.md' | Select-Object Name\""
91+
```
92+
93+
期望:文件名里的标题段是真实对话标题(如"核查最新聊天并检查075实验代码问题"),不是 `#-AGENTS.md-instructions` 或乱码。
94+
95+
**只有看到正确文件名才算验证通过。**
96+
97+
### Step 5: 确认后才能 git push & 版本号升级
98+
99+
验证通过之前不要 push,不要升版本号,不要说"已修好"。
100+
101+
---
102+
103+
## 已知 Bug 优先级
104+
105+
| 优先级 | 问题 | 状态 |
106+
|--------|------|------|
107+
| P0 | Codex 会话标题乱(AGENTS.md 注入) | v0.8.10 已修,待验证 |
108+
| P1 | CodexWatcher 把所有会话都导出到当前 workspace,不按 cwd 分类 | 未修 |
109+
110+
P1 直接导致用户在正确的项目目录下找不到对应会话的导出文件。不要在 P0 验证通过前就去改 P1,也不要在 P1 未修的情况下假装问题解决了。
111+
112+
---
113+
114+
## 禁止行为
115+
116+
- 改完代码 build 成功就宣布"修好了" — build 成功只说明编译通过,不代表功能正确
117+
- 在本地验证文件路径 / 标题逻辑 — 插件在 4090 跑,本地验不到真实数据
118+
- 跳过 Step 4 的手动 re-export — 现有旧文件名不会自动更新,必须触发一次 export
119+
- 发现新 bug 后立刻跳过去修 — 先把当前 bug 闭环验证,再开新问题

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "claude-code-exporter",
33
"displayName": "Claude Code Exporter — Claude Code, Codex & Cursor Conversation History",
44
"description": "Export AI coding agent conversations to Markdown. Supports Claude Code (→ .claude-code-history/), OpenAI Codex (→ .codex-history/), and Cursor Composer (→ .cursor-history/). Features: auto-watch, session inject/import for claude --resume, and repair of thinking-block signature errors when switching API providers.",
5-
"version": "0.8.10",
5+
"version": "0.8.11",
66
"publisher": "myoontyee",
77
"engines": {
88
"vscode": "^1.85.0"

src/codexExporter.ts

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class CodexExporter {
3838
};
3939
}
4040

41-
/** Export a single Codex session JSONL to <workspaceRoot>/.codex-history/ */
41+
/** Export a single Codex session JSONL to <cwd>/.codex-history/ (falls back to workspaceRoot) */
4242
exportSessionToWorkspace(
4343
sessionFilePath: string,
4444
workspaceRoot: string,
@@ -58,7 +58,9 @@ export class CodexExporter {
5858
? this.renderCompact(session, options)
5959
: this.renderReadable(session, options);
6060

61-
const outDir = path.join(workspaceRoot, '.codex-history');
61+
// P1 fix: export to session's cwd if it exists, not the active workspace
62+
const cwdBase = session.cwd && fs.existsSync(session.cwd) ? session.cwd : workspaceRoot;
63+
const outDir = path.join(cwdBase, '.codex-history');
6264
fs.mkdirSync(outDir, { recursive: true });
6365

6466
// De-dup by shortId (same session updated = overwrite, not create new file)
@@ -98,19 +100,9 @@ export class CodexExporter {
98100
const ts = session.endTime || session.startTime;
99101
const date = ts ? fmtFileTimestamp(new Date(ts)) : 'unknown-date';
100102

101-
let preview = '';
102-
for (const msg of session.messages) {
103-
if (msg.role === 'user') {
104-
const tb = msg.blocks.find((b) => b.type === 'text') as { type: 'text'; text: string } | undefined;
105-
if (tb?.text?.trim()) {
106-
const text = tb.text.trim();
107-
if (text.startsWith('<environment_context>')) continue;
108-
preview = text.slice(0, 40);
109-
break;
110-
}
111-
}
112-
}
113-
preview = preview
103+
// Use codexSessionTitle which prioritises threadName over raw messages
104+
const title = codexSessionTitle(session, 40);
105+
const preview = title
114106
.replace(/[\\/:*?"<>|\r\n]/g, '')
115107
.replace(/\s+/g, '-')
116108
.slice(0, 40);

0 commit comments

Comments
 (0)