opencode-diff-viewer 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -57
- package/dist/index.js +72 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,44 +3,38 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/opencode-diff-viewer)
|
|
4
4
|
[](https://www.npmjs.com/package/opencode-diff-viewer)
|
|
5
5
|
|
|
6
|
-
一个 OpenCode 插件,使用 [lumen](https://github.com/jnsahaj/lumen) 提供美观的 TUI diff 查看功能。
|
|
6
|
+
一个 OpenCode 插件,使用 [lumen](https://github.com/jnsahaj/lumen) + [tmux](https://github.com/tmux/tmux) 提供美观的 TUI diff 查看功能。
|
|
7
7
|
|
|
8
8
|
## 功能特性
|
|
9
9
|
|
|
10
|
-
- ✨ **自动安装 lumen** -
|
|
10
|
+
- ✨ **自动安装 tmux 和 lumen** - 插件会自动检测并安装依赖
|
|
11
11
|
- 🚀 **一键查看 diff** - 使用 `/diff` 命令快速查看代码变更
|
|
12
|
-
- 🔧
|
|
12
|
+
- 🔧 **tmux 集成** - 在后台 tmux 会话中运行 lumen
|
|
13
13
|
- 🤖 **LLM 工具集成** - LLM 可自动调用 `view_diff` 工具
|
|
14
14
|
|
|
15
15
|
## 前置条件
|
|
16
16
|
|
|
17
|
-
###
|
|
17
|
+
### 自动安装
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
插件会在启动时自动检查并安装以下依赖:
|
|
20
20
|
|
|
21
|
-
**
|
|
22
|
-
|
|
23
|
-
brew install jnsahaj/lumen/lumen
|
|
24
|
-
```
|
|
21
|
+
1. **tmux** - 终端复用器
|
|
22
|
+
2. **lumen** - TUI diff 查看器
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
bun install jnsahaj/lumen/lumen
|
|
29
|
-
```
|
|
24
|
+
### 手动安装(如果自动安装失败)
|
|
30
25
|
|
|
31
|
-
**
|
|
26
|
+
**tmux**:
|
|
32
27
|
```bash
|
|
33
|
-
|
|
28
|
+
brew install tmux
|
|
29
|
+
# or
|
|
30
|
+
apt install tmux
|
|
34
31
|
```
|
|
35
32
|
|
|
36
|
-
**
|
|
37
|
-
下载 [lumen releases](https://github.com/jnsahaj/lumen/releases) 并添加到 PATH
|
|
38
|
-
|
|
39
|
-
### 2. Git 仓库
|
|
40
|
-
|
|
41
|
-
确保项目是 git 仓库,并且有修改的文件:
|
|
33
|
+
**lumen**:
|
|
42
34
|
```bash
|
|
43
|
-
|
|
35
|
+
brew install jnsahaj/lumen/lumen
|
|
36
|
+
# or
|
|
37
|
+
cargo install lumen
|
|
44
38
|
```
|
|
45
39
|
|
|
46
40
|
## 安装(全局配置)
|
|
@@ -68,7 +62,7 @@ cat > ~/.config/opencode/opencode.json << 'EOF'
|
|
|
68
62
|
{
|
|
69
63
|
"command": {
|
|
70
64
|
"diff": {
|
|
71
|
-
"template": "View git diff using lumen
|
|
65
|
+
"template": "View git diff using lumen in tmux.",
|
|
72
66
|
"description": "View diff of modified files using lumen TUI"
|
|
73
67
|
}
|
|
74
68
|
},
|
|
@@ -96,10 +90,19 @@ EOF
|
|
|
96
90
|
|
|
97
91
|
LLM 可以自动调用 `view_diff` 工具来展示代码变更。无需手动操作,LLM 会根据对话上下文智能判断何时需要展示 diff。
|
|
98
92
|
|
|
99
|
-
|
|
93
|
+
### 查看 lumen
|
|
94
|
+
|
|
95
|
+
执行 `/diff` 后,lumen 会在 tmux 会话中运行。要查看 lumen:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
tmux attach -t opencode-diff-viewer
|
|
99
|
+
```
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
**tmux 快捷键**:
|
|
102
|
+
- `Ctrl+B` 然后 `D` - 分离会话(回到 OpenCode)
|
|
103
|
+
- `Ctrl+B` 然后 `?` - 查看所有快捷键
|
|
102
104
|
|
|
105
|
+
**lumen 快捷键**:
|
|
103
106
|
| 快捷键 | 功能 |
|
|
104
107
|
|--------|------|
|
|
105
108
|
| `j` / `k` 或 `↑` / `↓` | 上/下移动 |
|
|
@@ -110,15 +113,23 @@ LLM 可以自动调用 `view_diff` 工具来展示代码变更。无需手动操
|
|
|
110
113
|
|
|
111
114
|
## 故障排除
|
|
112
115
|
|
|
113
|
-
### 1.
|
|
116
|
+
### 1. tmux 未安装
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
❌ tmux is not installed
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**解决方案**: 手动安装 tmux(见上方手动安装)
|
|
123
|
+
|
|
124
|
+
### 2. lumen 未安装
|
|
114
125
|
|
|
115
126
|
```
|
|
116
127
|
❌ lumen is not installed
|
|
117
128
|
```
|
|
118
129
|
|
|
119
|
-
**解决方案**: 手动安装 lumen
|
|
130
|
+
**解决方案**: 手动安装 lumen(见上方手动安装)
|
|
120
131
|
|
|
121
|
-
###
|
|
132
|
+
### 3. 没有修改的文件
|
|
122
133
|
|
|
123
134
|
```
|
|
124
135
|
📝 No modified files
|
|
@@ -129,12 +140,6 @@ LLM 可以自动调用 `view_diff` 工具来展示代码变更。无需手动操
|
|
|
129
140
|
git add .
|
|
130
141
|
```
|
|
131
142
|
|
|
132
|
-
### 3. 新终端未打开
|
|
133
|
-
|
|
134
|
-
检查终端模拟器是否支持:
|
|
135
|
-
- macOS: Terminal.app
|
|
136
|
-
- Linux: gnome-terminal 或 xterm
|
|
137
|
-
|
|
138
143
|
### 4. 插件未加载
|
|
139
144
|
|
|
140
145
|
检查全局配置文件是否正确:
|
|
@@ -142,24 +147,12 @@ git add .
|
|
|
142
147
|
cat ~/.config/opencode/opencode.json
|
|
143
148
|
```
|
|
144
149
|
|
|
145
|
-
确保配置正确:
|
|
146
|
-
```json
|
|
147
|
-
{
|
|
148
|
-
"command": {
|
|
149
|
-
"diff": {
|
|
150
|
-
"template": "View git diff using lumen TUI.",
|
|
151
|
-
"description": "View diff of modified files using lumen TUI"
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
"plugin": ["opencode-diff-viewer"]
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
150
|
## 工作原理
|
|
159
151
|
|
|
160
|
-
1.
|
|
161
|
-
2.
|
|
162
|
-
3.
|
|
152
|
+
1. **检测依赖** - 插件启动时检查 tmux 和 lumen
|
|
153
|
+
2. **自动安装** - 如果未安装,自动通过 brew 或 cargo 安装
|
|
154
|
+
3. **创建 tmux 会话** - 执行 `/diff` 时创建后台 tmux 会话
|
|
155
|
+
4. **运行 lumen** - 在 tmux 会话中运行 lumen diff
|
|
163
156
|
|
|
164
157
|
## 项目结构
|
|
165
158
|
|
|
@@ -184,18 +177,11 @@ cd opencode-diff-viewer
|
|
|
184
177
|
|
|
185
178
|
# 安装依赖
|
|
186
179
|
npm install
|
|
187
|
-
# 或
|
|
188
|
-
pnpm install
|
|
189
|
-
# 或
|
|
190
|
-
bun install
|
|
191
180
|
|
|
192
181
|
# 构建
|
|
193
182
|
npm run build
|
|
194
183
|
|
|
195
184
|
# 链接本地包
|
|
196
|
-
npm link
|
|
197
|
-
|
|
198
|
-
# 在全局使用
|
|
199
185
|
npm link -g opencode-diff-viewer
|
|
200
186
|
```
|
|
201
187
|
|
|
@@ -213,6 +199,7 @@ npm publish
|
|
|
213
199
|
|
|
214
200
|
## 依赖
|
|
215
201
|
|
|
202
|
+
- [tmux](https://github.com/tmux/tmux) - 终端复用器
|
|
216
203
|
- [lumen](https://github.com/jnsahaj/lumen) - TUI Diff 查看器
|
|
217
204
|
- [@opencode-ai/plugin](https://www.npmjs.com/package/@opencode-ai/plugin) - OpenCode 插件 SDK
|
|
218
205
|
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,15 @@ export const DiffViewerPlugin = async ({ project, client, $, directory, worktree
|
|
|
9
9
|
return false;
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
|
+
const isTmuxInstalled = async () => {
|
|
13
|
+
try {
|
|
14
|
+
await $ `which tmux`;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
12
21
|
const isBrewInstalled = async () => {
|
|
13
22
|
try {
|
|
14
23
|
await $ `which brew`;
|
|
@@ -51,6 +60,21 @@ export const DiffViewerPlugin = async ({ project, client, $, directory, worktree
|
|
|
51
60
|
error: "Neither brew nor cargo available. Please install lumen manually:\n brew install jnsahaj/lumen/lumen\n # or\n cargo install lumen"
|
|
52
61
|
};
|
|
53
62
|
};
|
|
63
|
+
const installTmux = async () => {
|
|
64
|
+
if (await isBrewInstalled()) {
|
|
65
|
+
try {
|
|
66
|
+
await $ `brew install tmux`;
|
|
67
|
+
return { success: true, method: "brew" };
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
console.warn(`brew install tmux failed: ${e}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
success: false,
|
|
75
|
+
error: "Please install tmux manually:\n brew install tmux\n # or\n apt install tmux"
|
|
76
|
+
};
|
|
77
|
+
};
|
|
54
78
|
const ensureLumenInstalled = async () => {
|
|
55
79
|
if (await isLumenInstalled()) {
|
|
56
80
|
return { installed: true };
|
|
@@ -61,7 +85,25 @@ export const DiffViewerPlugin = async ({ project, client, $, directory, worktree
|
|
|
61
85
|
}
|
|
62
86
|
return { installed: false, message: `❌ ${result.error}` };
|
|
63
87
|
};
|
|
64
|
-
|
|
88
|
+
const ensureTmuxInstalled = async () => {
|
|
89
|
+
if (await isTmuxInstalled()) {
|
|
90
|
+
return { installed: true };
|
|
91
|
+
}
|
|
92
|
+
const result = await installTmux();
|
|
93
|
+
if (result.success) {
|
|
94
|
+
return { installed: true, message: `✅ tmux installed via ${result.method}` };
|
|
95
|
+
}
|
|
96
|
+
return { installed: false, message: `❌ ${result.error}` };
|
|
97
|
+
};
|
|
98
|
+
// Check and install dependencies on startup
|
|
99
|
+
const tmuxCheck = await ensureTmuxInstalled();
|
|
100
|
+
if (!tmuxCheck.installed) {
|
|
101
|
+
console.warn(tmuxCheck.message);
|
|
102
|
+
}
|
|
103
|
+
const lumenCheck = await ensureLumenInstalled();
|
|
104
|
+
if (!lumenCheck.installed) {
|
|
105
|
+
console.warn(lumenCheck.message);
|
|
106
|
+
}
|
|
65
107
|
const getModifiedFiles = async () => {
|
|
66
108
|
try {
|
|
67
109
|
const unstaged = await $ `git diff --name-only`.text();
|
|
@@ -77,6 +119,18 @@ export const DiffViewerPlugin = async ({ project, client, $, directory, worktree
|
|
|
77
119
|
}
|
|
78
120
|
};
|
|
79
121
|
const launchDiffViewer = async (files) => {
|
|
122
|
+
// Check tmux
|
|
123
|
+
if (!await isTmuxInstalled()) {
|
|
124
|
+
return `❌ tmux is not installed.
|
|
125
|
+
|
|
126
|
+
To install:
|
|
127
|
+
brew install tmux
|
|
128
|
+
# or
|
|
129
|
+
apt install tmux
|
|
130
|
+
|
|
131
|
+
Then restart OpenCode.`;
|
|
132
|
+
}
|
|
133
|
+
// Check lumen
|
|
80
134
|
if (!await isLumenInstalled()) {
|
|
81
135
|
return `❌ lumen is not installed.
|
|
82
136
|
|
|
@@ -93,40 +147,27 @@ Then restart OpenCode.`;
|
|
|
93
147
|
}
|
|
94
148
|
const fileList = modifiedFiles.map(f => ` • ${f}`).join('\n');
|
|
95
149
|
const fileArgs = modifiedFiles.map(f => `"${f}"`).join(' ');
|
|
150
|
+
const sessionName = "opencode-diff-viewer";
|
|
96
151
|
const cmd = `cd "${directory}" && lumen diff ${fileArgs}`;
|
|
97
|
-
const platform = process.platform;
|
|
98
|
-
// Try to launch in new terminal
|
|
99
|
-
let launched = false;
|
|
100
|
-
let errorMsg = "";
|
|
101
152
|
try {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
catch (e) {
|
|
117
|
-
errorMsg = "No terminal emulator found (gnome-terminal/xterm)";
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
153
|
+
// Kill existing session if it exists
|
|
154
|
+
await $ `tmux kill-session -t "${sessionName}" 2>/dev/null || true`;
|
|
155
|
+
// Create new tmux session
|
|
156
|
+
await $ `tmux new-session -d -s "${sessionName}" "${cmd}"`;
|
|
157
|
+
return `✅ Opened lumen in tmux session "${sessionName}":\n${fileList}\n\nTo use lumen:
|
|
158
|
+
1. Run: tmux attach -t "${sessionName}"
|
|
159
|
+
2. Navigate: j/k or arrows, {/} for hunks
|
|
160
|
+
3. Detach: Ctrl+B then D
|
|
161
|
+
|
|
162
|
+
Keybindings:
|
|
163
|
+
j/k or ↑/↓: Navigate {/}: Jump hunks
|
|
164
|
+
tab: Sidebar e: Edit file
|
|
165
|
+
q: Quit`;
|
|
121
166
|
}
|
|
122
167
|
catch (e) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (launched) {
|
|
126
|
-
return `✅ Opened lumen diff viewer:\n${fileList}\n\nKeybindings:\n j/k: Navigate {/}: Jump hunks tab: Sidebar e: Edit q: Quit`;
|
|
168
|
+
return `❌ Failed to launch tmux session: ${e.message || e}\n\nTry manually:
|
|
169
|
+
tmux new-session -s "${sessionName}" "${cmd}"`;
|
|
127
170
|
}
|
|
128
|
-
// If we couldn't launch, show manual instructions
|
|
129
|
-
return `📺 Could not open terminal automatically.\n\nTo view diffs in lumen:\n1. Open a new terminal\n2. Run:\n ${cmd}\n\nModified files:\n${fileList}`;
|
|
130
171
|
};
|
|
131
172
|
return {
|
|
132
173
|
"tui.command.execute": async (input, output) => {
|
|
@@ -141,7 +182,7 @@ Then restart OpenCode.`;
|
|
|
141
182
|
},
|
|
142
183
|
tool: {
|
|
143
184
|
view_diff: tool({
|
|
144
|
-
description: "Open the lumen diff viewer
|
|
185
|
+
description: "Open the lumen diff viewer in a tmux session.",
|
|
145
186
|
args: {
|
|
146
187
|
file: tool.schema.string().optional().describe("Optional: specific file path"),
|
|
147
188
|
},
|