opencode-diff-viewer 1.0.6 → 1.0.7
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 +37 -24
- package/dist/index.js +49 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,33 +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 插件,使用 [
|
|
6
|
+
一个 OpenCode 插件,使用 [lumen](https://github.com/jnsahaj/lumen) 提供美观的 TUI diff 查看功能。
|
|
7
7
|
|
|
8
8
|
## 功能特性
|
|
9
9
|
|
|
10
|
-
- ✨ **自动安装
|
|
10
|
+
- ✨ **自动安装 lumen** - 插件会自动检测并安装 lumen 依赖
|
|
11
11
|
- 🚀 **一键查看 diff** - 使用 `/diff` 命令快速查看代码变更
|
|
12
|
-
-
|
|
12
|
+
- 🔧 **智能终端适配** - 自动检测操作系统,打开新终端窗口展示 diff
|
|
13
13
|
- 🤖 **LLM 工具集成** - LLM 可自动调用 `view_diff` 工具
|
|
14
14
|
|
|
15
15
|
## 前置条件
|
|
16
16
|
|
|
17
|
-
### 1. 安装
|
|
17
|
+
### 1. 安装 lumen
|
|
18
18
|
|
|
19
|
-
插件会自动尝试安装
|
|
19
|
+
插件会自动尝试安装 lumen,如果自动安装失败,需要手动安装:
|
|
20
20
|
|
|
21
21
|
**macOS / Linux (Homebrew)**:
|
|
22
22
|
```bash
|
|
23
|
-
brew install
|
|
23
|
+
brew install jnsahaj/lumen/lumen
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Bun**:
|
|
27
|
+
```bash
|
|
28
|
+
bun install jnsahaj/lumen/lumen
|
|
24
29
|
```
|
|
25
30
|
|
|
26
31
|
**Cargo (Rust)**:
|
|
27
32
|
```bash
|
|
28
|
-
cargo install
|
|
33
|
+
cargo install lumen
|
|
29
34
|
```
|
|
30
35
|
|
|
31
36
|
**Windows**:
|
|
32
|
-
下载 [
|
|
37
|
+
下载 [lumen releases](https://github.com/jnsahaj/lumen/releases) 并添加到 PATH
|
|
33
38
|
|
|
34
39
|
### 2. Git 仓库
|
|
35
40
|
|
|
@@ -63,8 +68,8 @@ cat > ~/.config/opencode/opencode.json << 'EOF'
|
|
|
63
68
|
{
|
|
64
69
|
"command": {
|
|
65
70
|
"diff": {
|
|
66
|
-
"template": "View git diff
|
|
67
|
-
"description": "
|
|
71
|
+
"template": "View git diff using lumen TUI.",
|
|
72
|
+
"description": "View diff of modified files using lumen TUI"
|
|
68
73
|
}
|
|
69
74
|
},
|
|
70
75
|
"plugin": ["opencode-diff-viewer"]
|
|
@@ -91,25 +96,27 @@ EOF
|
|
|
91
96
|
|
|
92
97
|
LLM 可以自动调用 `view_diff` 工具来展示代码变更。无需手动操作,LLM 会根据对话上下文智能判断何时需要展示 diff。
|
|
93
98
|
|
|
94
|
-
##
|
|
99
|
+
## lumen 快捷键
|
|
95
100
|
|
|
96
|
-
在 diff
|
|
101
|
+
在 lumen diff 查看器中:
|
|
97
102
|
|
|
98
103
|
| 快捷键 | 功能 |
|
|
99
104
|
|--------|------|
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
105
|
+
| `j` / `k` 或 `↑` / `↓` | 上/下移动 |
|
|
106
|
+
| `{` / `}` | 跳转到上/下一个变更块 |
|
|
107
|
+
| `Tab` | 切换侧边栏 |
|
|
108
|
+
| `e` | 在编辑器中打开文件 |
|
|
109
|
+
| `q` | 退出 |
|
|
103
110
|
|
|
104
111
|
## 故障排除
|
|
105
112
|
|
|
106
|
-
### 1.
|
|
113
|
+
### 1. lumen 未安装
|
|
107
114
|
|
|
108
115
|
```
|
|
109
|
-
❌
|
|
116
|
+
❌ lumen is not installed
|
|
110
117
|
```
|
|
111
118
|
|
|
112
|
-
**解决方案**: 手动安装
|
|
119
|
+
**解决方案**: 手动安装 lumen(见上方前置条件)
|
|
113
120
|
|
|
114
121
|
### 2. 没有修改的文件
|
|
115
122
|
|
|
@@ -122,7 +129,13 @@ LLM 可以自动调用 `view_diff` 工具来展示代码变更。无需手动操
|
|
|
122
129
|
git add .
|
|
123
130
|
```
|
|
124
131
|
|
|
125
|
-
### 3.
|
|
132
|
+
### 3. 新终端未打开
|
|
133
|
+
|
|
134
|
+
检查终端模拟器是否支持:
|
|
135
|
+
- macOS: Terminal.app
|
|
136
|
+
- Linux: gnome-terminal 或 xterm
|
|
137
|
+
|
|
138
|
+
### 4. 插件未加载
|
|
126
139
|
|
|
127
140
|
检查全局配置文件是否正确:
|
|
128
141
|
```bash
|
|
@@ -134,8 +147,8 @@ cat ~/.config/opencode/opencode.json
|
|
|
134
147
|
{
|
|
135
148
|
"command": {
|
|
136
149
|
"diff": {
|
|
137
|
-
"template": "View git diff
|
|
138
|
-
"description": "
|
|
150
|
+
"template": "View git diff using lumen TUI.",
|
|
151
|
+
"description": "View diff of modified files using lumen TUI"
|
|
139
152
|
}
|
|
140
153
|
},
|
|
141
154
|
"plugin": ["opencode-diff-viewer"]
|
|
@@ -145,8 +158,8 @@ cat ~/.config/opencode/opencode.json
|
|
|
145
158
|
## 工作原理
|
|
146
159
|
|
|
147
160
|
1. **检测修改文件** - 插件使用 `git diff` 获取已暂存和未暂存的修改
|
|
148
|
-
2.
|
|
149
|
-
3. **自动安装** - 插件启动时检查
|
|
161
|
+
2. **启动 lumen** - 在新终端窗口中运行 `lumen diff --file <files>`
|
|
162
|
+
3. **自动安装** - 插件启动时检查 lumen,未安装则自动安装
|
|
150
163
|
|
|
151
164
|
## 项目结构
|
|
152
165
|
|
|
@@ -200,7 +213,7 @@ npm publish
|
|
|
200
213
|
|
|
201
214
|
## 依赖
|
|
202
215
|
|
|
203
|
-
- [
|
|
216
|
+
- [lumen](https://github.com/jnsahaj/lumen) - TUI Diff 查看器
|
|
204
217
|
- [@opencode-ai/plugin](https://www.npmjs.com/package/@opencode-ai/plugin) - OpenCode 插件 SDK
|
|
205
218
|
|
|
206
219
|
## License
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin";
|
|
2
2
|
export const DiffViewerPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
3
|
-
const
|
|
3
|
+
const isLumenInstalled = async () => {
|
|
4
4
|
try {
|
|
5
|
-
await $ `which
|
|
5
|
+
await $ `which lumen`;
|
|
6
6
|
return true;
|
|
7
7
|
}
|
|
8
8
|
catch {
|
|
@@ -27,10 +27,10 @@ export const DiffViewerPlugin = async ({ project, client, $, directory, worktree
|
|
|
27
27
|
return false;
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
|
-
const
|
|
30
|
+
const installLumen = async () => {
|
|
31
31
|
if (await isBrewInstalled()) {
|
|
32
32
|
try {
|
|
33
|
-
await $ `brew install
|
|
33
|
+
await $ `brew install jnsahaj/lumen/lumen`;
|
|
34
34
|
return { success: true, method: "brew" };
|
|
35
35
|
}
|
|
36
36
|
catch (e) {
|
|
@@ -39,7 +39,7 @@ export const DiffViewerPlugin = async ({ project, client, $, directory, worktree
|
|
|
39
39
|
}
|
|
40
40
|
if (await isCargoInstalled()) {
|
|
41
41
|
try {
|
|
42
|
-
await $ `cargo install
|
|
42
|
+
await $ `cargo install lumen`;
|
|
43
43
|
return { success: true, method: "cargo" };
|
|
44
44
|
}
|
|
45
45
|
catch (e) {
|
|
@@ -48,20 +48,20 @@ export const DiffViewerPlugin = async ({ project, client, $, directory, worktree
|
|
|
48
48
|
}
|
|
49
49
|
return {
|
|
50
50
|
success: false,
|
|
51
|
-
error: "Neither brew nor cargo available. Please install
|
|
51
|
+
error: "Neither brew nor cargo available. Please install lumen manually:\n brew install jnsahaj/lumen/lumen\n # or\n cargo install lumen"
|
|
52
52
|
};
|
|
53
53
|
};
|
|
54
|
-
const
|
|
55
|
-
if (await
|
|
54
|
+
const ensureLumenInstalled = async () => {
|
|
55
|
+
if (await isLumenInstalled()) {
|
|
56
56
|
return { installed: true };
|
|
57
57
|
}
|
|
58
|
-
const result = await
|
|
58
|
+
const result = await installLumen();
|
|
59
59
|
if (result.success) {
|
|
60
|
-
return { installed: true, message: `✅
|
|
60
|
+
return { installed: true, message: `✅ lumen installed via ${result.method}` };
|
|
61
61
|
}
|
|
62
62
|
return { installed: false, message: `❌ ${result.error}` };
|
|
63
63
|
};
|
|
64
|
-
await
|
|
64
|
+
await ensureLumenInstalled();
|
|
65
65
|
const getModifiedFiles = async () => {
|
|
66
66
|
try {
|
|
67
67
|
const unstaged = await $ `git diff --name-only`.text();
|
|
@@ -76,14 +76,14 @@ export const DiffViewerPlugin = async ({ project, client, $, directory, worktree
|
|
|
76
76
|
return [];
|
|
77
77
|
}
|
|
78
78
|
};
|
|
79
|
-
const
|
|
80
|
-
if (!await
|
|
81
|
-
return `❌
|
|
79
|
+
const launchDiffViewer = async (files) => {
|
|
80
|
+
if (!await isLumenInstalled()) {
|
|
81
|
+
return `❌ lumen is not installed.
|
|
82
82
|
|
|
83
83
|
To install:
|
|
84
|
-
brew install
|
|
84
|
+
brew install jnsahaj/lumen/lumen
|
|
85
85
|
# or
|
|
86
|
-
cargo install
|
|
86
|
+
cargo install lumen
|
|
87
87
|
|
|
88
88
|
Then restart OpenCode.`;
|
|
89
89
|
}
|
|
@@ -91,38 +91,49 @@ Then restart OpenCode.`;
|
|
|
91
91
|
if (modifiedFiles.length === 0) {
|
|
92
92
|
return "📝 No modified files.\n\nRun \`git add .\` to stage changes first.";
|
|
93
93
|
}
|
|
94
|
+
const fileList = modifiedFiles.map(f => ` • ${f}`).join('\n');
|
|
95
|
+
const fileArgs = modifiedFiles.map(f => `"${f}"`).join(' ');
|
|
96
|
+
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 = "";
|
|
94
101
|
try {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const stagedDiff = await $ `cd "${directory}" && git diff --staged`.text();
|
|
99
|
-
if (stagedDiff.trim()) {
|
|
100
|
-
diffOutput += "=== STAGED CHANGES ===\n\n";
|
|
101
|
-
diffOutput += await $ `cd "${directory}" && git diff --staged | delta --pager=never`.text();
|
|
102
|
+
if (platform === 'darwin') {
|
|
103
|
+
await $ `osascript -e 'tell application "Terminal" to do script "${cmd}; exit"'`;
|
|
104
|
+
launched = true;
|
|
102
105
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
else if (platform === 'linux') {
|
|
107
|
+
try {
|
|
108
|
+
await $ `which gnome-terminal && gnome-terminal -- bash -c "${cmd}; read -p 'Press Enter to close...'" `;
|
|
109
|
+
launched = true;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
try {
|
|
113
|
+
await $ `which xterm && xterm -e "bash -c '${cmd}; read -p Press Enter to close...'" `;
|
|
114
|
+
launched = true;
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
errorMsg = "No terminal emulator found (gnome-terminal/xterm)";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
109
120
|
}
|
|
110
|
-
if (!diffOutput.trim()) {
|
|
111
|
-
return "📝 No changes to show.";
|
|
112
|
-
}
|
|
113
|
-
const fileList = modifiedFiles.map(f => ` • ${f}`).join('\n');
|
|
114
|
-
return `✅ Modified files (${modifiedFiles.length}):\n${fileList}\n\n${diffOutput}`;
|
|
115
121
|
}
|
|
116
122
|
catch (e) {
|
|
117
|
-
|
|
123
|
+
errorMsg = e.message || "Unknown error";
|
|
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`;
|
|
118
127
|
}
|
|
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}`;
|
|
119
130
|
};
|
|
120
131
|
return {
|
|
121
132
|
"tui.command.execute": async (input, output) => {
|
|
122
133
|
if (input.command === "diff") {
|
|
123
134
|
const files = input.args?.trim() ? [input.args.trim()] : undefined;
|
|
124
135
|
output.handled = true;
|
|
125
|
-
output.result = await
|
|
136
|
+
output.result = await launchDiffViewer(files);
|
|
126
137
|
}
|
|
127
138
|
},
|
|
128
139
|
"file.edited": async ({ event }) => {
|
|
@@ -130,12 +141,12 @@ Then restart OpenCode.`;
|
|
|
130
141
|
},
|
|
131
142
|
tool: {
|
|
132
143
|
view_diff: tool({
|
|
133
|
-
description: "
|
|
144
|
+
description: "Open the lumen diff viewer to show git diff for modified files.",
|
|
134
145
|
args: {
|
|
135
146
|
file: tool.schema.string().optional().describe("Optional: specific file path"),
|
|
136
147
|
},
|
|
137
148
|
async execute(args, ctx) {
|
|
138
|
-
return await
|
|
149
|
+
return await launchDiffViewer(args.file ? [args.file] : undefined);
|
|
139
150
|
},
|
|
140
151
|
}),
|
|
141
152
|
},
|