opencode-agent-ghost-panel 0.1.0

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 ADDED
@@ -0,0 +1,248 @@
1
+ # AGP OpenCode Plugin
2
+
3
+ Agent Ghost Panel 的 OpenCode 插件,提供无缝的终端多路复用集成。
4
+
5
+ ## ✨ 特性
6
+
7
+ - 🔌 **自动启动**:OpenCode 启动时自动启动 AGP 守护进程
8
+ - 🛠️ **原生命令**:直接在 OpenCode 中使用 `/diff`、`/logs` 等命令
9
+ - 🌙 **幽灵模式**:Agent 在后台静默运行,不阻塞交互
10
+ - 🎨 **语法高亮**:通过 lumen 实现 git diff 语法高亮
11
+ - 🔄 **交互支持**:支持 ssh、sudo 等交互式命令
12
+ - 📡 **多路复用**:tmux 窗口管理
13
+
14
+ ## 📦 安装
15
+
16
+ ```bash
17
+ # 1. 安装 AGP
18
+ pip install -e .
19
+
20
+ # 2. 安装 OpenCode 插件
21
+ agp install opencode
22
+
23
+ # 3. 安装 lumen(diff 高亮需要)
24
+ pip install lumen
25
+
26
+ # 4. 重启 OpenCode,插件自动加载
27
+ ```
28
+
29
+ ## 🚀 使用方法
30
+
31
+ ### 启动 OpenCode + AGP
32
+
33
+ ```bash
34
+ # 一键启动 OpenCode + AGP(自动管理 tmux)
35
+ agp opencode
36
+
37
+ # 这将自动:
38
+ # 1. 启动 AGP 守护进程
39
+ # 2. 创建 tmux 会话 (agp-opencode)
40
+ # 3. 启动 OpenCode
41
+ # 4. 加载 AGP 插件
42
+ ```
43
+
44
+ ### OpenCode 命令
45
+
46
+ 启动 OpenCode 后,直接在对话中使用以下命令:
47
+
48
+ | 命令 | 别名 | 功能 |
49
+ |------|------|------|
50
+ | `/diff` | `/d` | 在 tmux 新窗口显示 git diff(带高亮) |
51
+ | `/diff <file>` | `/d <file>` | 显示指定文件的 diff |
52
+ | `/logs <file>` | `/l` | 实时监控日志文件 |
53
+ | `/interactive` | `/i` | 打开交互式终端(ssh/sudo 等) |
54
+ | `/status` | `/s` | 查看 AGP 状态 |
55
+ | `/sessions` | `/ss` | 列出所有 tmux 会话 |
56
+
57
+ ### 使用示例
58
+
59
+ ```
60
+ 用户: 查看当前的 git 修改
61
+ Agent: 好的,让我用 AGP 在 diff 窗口显示修改
62
+ [执行 /diff 命令]
63
+ ✅ 已在 tmux diff 窗口显示 git diff(带颜色高亮)
64
+
65
+ 用户: 需要登录服务器
66
+ Agent: 好的,我来创建一个交互式终端
67
+ [执行 /interactive 命令]
68
+ ✅ 交互式终端已创建,您可以输入 SSH 命令
69
+
70
+ 用户: 监控应用日志
71
+ Agent: 好的,启动日志监控
72
+ [执行 /logs app.log 命令]
73
+ ✅ 日志监控已启动
74
+ ```
75
+
76
+ ## ⌨️ tmux 快捷键
77
+
78
+ 在 tmux 窗口中:
79
+
80
+ ```
81
+ Ctrl+b, n # 下一个窗口
82
+ Ctrl+b, p # 上一个窗口
83
+ Ctrl+b, 0 # 切换到 OpenCode 窗口
84
+ Ctrl+b, 1 # 切换到 diff 窗口
85
+ Ctrl+b, 2 # 切换到 logs 窗口
86
+ Ctrl+b, 3 # 切换到 interactive 窗口
87
+ Ctrl+b, d # 分离会话(保留后台运行)
88
+ ```
89
+
90
+ 状态栏会显示当前窗口的操作提示。
91
+
92
+ ## 🏗️ 架构
93
+
94
+ ```
95
+ ┌─────────────────────────────────────────────────────────┐
96
+ │ OpenCode │
97
+ │ │
98
+ │ ┌───────────────────────────────────────────────┐ │
99
+ │ │ AGP 插件 │ │
100
+ │ │ • /diff → 创建 tmux diff 窗口 │ │
101
+ │ │ • /logs → 创建 tmux logs 窗口 │ │
102
+ │ │ • /interactive → 创建交互式终端 │ │
103
+ │ └───────────────────────────────────────────────┘ │
104
+ └─────────────────────────────────────────────────────────┘
105
+
106
+
107
+ ┌─────────────────────────────────────────────────────────┐
108
+ │ AGP 守护进程 (WebSocket) │
109
+ │ ws://127.0.0.1:8765 │
110
+ └─────────────────────────────────────────────────────────┘
111
+
112
+
113
+ ┌─────────────────────────────────────────────────────────┐
114
+ │ Tmux 会话 │
115
+ │ agp-opencode │
116
+ │ │
117
+ │ [opencode] ← OpenCode 主窗口 │
118
+ │ │ │
119
+ │ ├── [diff] ← lumen git diff(语法高亮) │
120
+ │ ├── [logs] ← tail -f 日志监控 │
121
+ │ └── [interactive] ← 交互式终端 │
122
+ └─────────────────────────────────────────────────────────┘
123
+ ```
124
+
125
+ ## 🔧 开发
126
+
127
+ ### 添加新命令
128
+
129
+ 1. 在 `__init__.py` 中添加命令处理函数:
130
+
131
+ ```python
132
+ async def _cmd_newcommand(args: list) -> Dict[str, Any]:
133
+ """新命令说明"""
134
+ # 1. 检查依赖
135
+ # 2. 执行 tmux 命令
136
+ # 3. 返回结果
137
+
138
+ return {
139
+ "success": True,
140
+ "message": "✅ 命令已执行",
141
+ "details": {...}
142
+ }
143
+ ```
144
+
145
+ 2. 在 `AGPPlugin.execute()` 中添加分支:
146
+
147
+ ```python
148
+ elif cmd in ["newcommand", "nc"]:
149
+ return await _cmd_newcommand(args)
150
+ ```
151
+
152
+ 3. 在 `get_commands()` 中注册命令:
153
+
154
+ ```python
155
+ {
156
+ "name": "newcommand",
157
+ "description": "新命令说明",
158
+ "usage": "/newcommand",
159
+ "aliases": ["nc"]
160
+ }
161
+ ```
162
+
163
+ ### 测试
164
+
165
+ ```bash
166
+ # 安装测试
167
+ agp install opencode
168
+
169
+ # 重启 OpenCode 测试
170
+ ```
171
+
172
+ ## 📝 命令说明
173
+
174
+ ### /diff
175
+
176
+ 在 tmux 新窗口显示 git diff,使用 lumen 实现语法高亮。
177
+
178
+ ```
179
+ /diff # 当前目录的 diff
180
+ /diff src/main.py # 指定文件的 diff
181
+ ```
182
+
183
+ 特点:
184
+ - 自动创建 tmux diff 窗口
185
+ - 使用 lumen 渲染,带语法高亮
186
+ - 状态栏显示操作提示
187
+
188
+ ### /logs
189
+
190
+ 实时监控日志文件。
191
+
192
+ ```
193
+ /logs app.log # 监控日志文件
194
+ /logs /var/log/app.log # 绝对路径
195
+ ```
196
+
197
+ 特点:
198
+ - 使用 `tail -f` 实时监控
199
+ - 新窗口显示,不阻塞 OpenCode
200
+ - 可以同时监控多个日志文件
201
+
202
+ ### /interactive
203
+
204
+ 打开交互式终端,用于需要用户输入的命令。
205
+
206
+ ```
207
+ /interactive # 打开空白交互终端
208
+ /interactive ssh user@host # 直接执行 ssh
209
+ ```
210
+
211
+ 适用场景:
212
+ - SSH 登录远程服务器
213
+ - sudo 命令需要密码
214
+ - 其他需要交互的命令
215
+
216
+ 使用后:
217
+ - 输入命令并回车执行
218
+ - 输入 `exit` 退出交互终端
219
+ - 使用 `Ctrl+b, d` 关闭窗口
220
+
221
+ ### /status
222
+
223
+ 查看 AGP 守护进程状态。
224
+
225
+ ```
226
+ /status # 或 /s
227
+ ```
228
+
229
+ 显示:
230
+ - 守护进程是否运行
231
+ - API 端点地址
232
+ - 会话数量
233
+
234
+ ### /sessions
235
+
236
+ 列出所有 tmux 会话。
237
+
238
+ ```
239
+ /sessions # 或 /ss
240
+ ```
241
+
242
+ ## 📄 许可证
243
+
244
+ MIT License
245
+
246
+ ## 🤝 贡献
247
+
248
+ 欢迎提交 Issue 或 Pull Request!
package/__init__.py ADDED
@@ -0,0 +1,338 @@
1
+ """
2
+ AGP Plugin for OpenCode - Agent Ghost Panel 集成
3
+ OpenCode 插件:终端多路复用与交互增强
4
+
5
+ 功能:
6
+ - /diff - 在 tmux 新窗口显示 git diff(使用 lumen)
7
+ - /status - 查看 AGP 状态
8
+ - /logs - 监控日志文件
9
+ - /interactive - 打开交互式终端
10
+ """
11
+
12
+ import json
13
+ import os
14
+ import socket
15
+ import subprocess
16
+ from typing import Any, Dict
17
+
18
+ # 插件元数据
19
+ PLUGIN_NAME = "agent-ghost-panel"
20
+ PLUGIN_VERSION = "0.2.0"
21
+ PLUGIN_DESCRIPTION = "基于 Tmux 的终端多路复用与交互增强"
22
+
23
+ # AGP 配置
24
+ AGP_HOST = "127.0.0.1"
25
+ AGP_PORT = 8765
26
+ AGP_TMUX_SESSION = "agp-opencode"
27
+
28
+
29
+ class AGPPlugin:
30
+ """AGP OpenCode 插件"""
31
+
32
+ name = PLUGIN_NAME
33
+ version = PLUGIN_VERSION
34
+ description = PLUGIN_DESCRIPTION
35
+
36
+ # 插件加载时调用
37
+ @staticmethod
38
+ def on_load():
39
+ print("🔌 AGP Plugin loaded: Agent Ghost Panel")
40
+
41
+ # 确保 AGP 守护进程运行
42
+ _ensure_daemon()
43
+
44
+ # 插件卸载时调用
45
+ @staticmethod
46
+ def on_unload():
47
+ print("👋 AGP Plugin unloaded")
48
+
49
+ # 获取命令列表
50
+ @staticmethod
51
+ def get_commands() -> list:
52
+ return [
53
+ {
54
+ "name": "diff",
55
+ "description": "在 tmux 新窗口显示 git diff(带颜色高亮)",
56
+ "usage": "/diff [file]",
57
+ "aliases": ["d"],
58
+ },
59
+ {
60
+ "name": "status",
61
+ "description": "查看 AGP 状态",
62
+ "usage": "/status",
63
+ "aliases": ["s"],
64
+ },
65
+ {
66
+ "name": "logs",
67
+ "description": "监控日志文件",
68
+ "usage": "/logs <log_file>",
69
+ "aliases": ["l"],
70
+ },
71
+ {
72
+ "name": "interactive",
73
+ "description": "打开交互式终端(ssh/sudo 等)",
74
+ "usage": "/interactive [command]",
75
+ "aliases": ["i"],
76
+ },
77
+ {
78
+ "name": "sessions",
79
+ "description": "列出所有 tmux 会话",
80
+ "usage": "/sessions",
81
+ "aliases": ["ss"],
82
+ },
83
+ ]
84
+
85
+ # 执行命令
86
+ @staticmethod
87
+ async def execute(command: str, args: list) -> Dict[str, Any]:
88
+ """执行 AGP 命令"""
89
+ cmd = command.lower()
90
+
91
+ if cmd in ["diff", "d"]:
92
+ return await _cmd_diff(args)
93
+ elif cmd in ["status", "s"]:
94
+ return await _cmd_status()
95
+ elif cmd in ["logs", "l"]:
96
+ return await _cmd_logs(args)
97
+ elif cmd in ["interactive", "i"]:
98
+ return await _cmd_interactive(args)
99
+ elif cmd in ["sessions", "ss"]:
100
+ return await _cmd_sessions()
101
+
102
+ return {"success": False, "error": f"Unknown command: {command}"}
103
+
104
+
105
+ # ============================================================================
106
+ # 命令实现
107
+ # ============================================================================
108
+
109
+
110
+ async def _cmd_diff(args: list) -> Dict[str, Any]:
111
+ """执行 /diff 命令 - 在 tmux 新窗口显示 diff"""
112
+ file_arg = args[0] if args else None
113
+
114
+ # 检查 tmux
115
+ result = subprocess.run(["which", "tmux"], capture_output=True)
116
+ if result.returncode != 0:
117
+ return {
118
+ "success": False,
119
+ "error": "tmux 未安装",
120
+ "message": "请安装 tmux: brew install tmux",
121
+ }
122
+
123
+ # 检查 lumen
124
+ result = subprocess.run(["which", "lumen"], capture_output=True)
125
+ if result.returncode != 0:
126
+ return {
127
+ "success": False,
128
+ "error": "lumen 未安装",
129
+ "message": "请安装 lumen: pip install lumen",
130
+ }
131
+
132
+ # 检查 tmux 会话
133
+ result = subprocess.run(["tmux", "has-session", "-t", AGP_TMUX_SESSION], capture_output=True)
134
+ if result.returncode != 0:
135
+ return {
136
+ "success": False,
137
+ "error": "tmux 会话不存在",
138
+ "message": "请先启动 OpenCode: agp opencode",
139
+ }
140
+
141
+ # 获取当前工作目录
142
+ cwd = os.getcwd()
143
+
144
+ # 构建命令
145
+ if file_arg:
146
+ cmd = f"cd {file_arg} && lumen diff"
147
+ window_name = f"diff:{os.path.basename(file_arg)}"
148
+ else:
149
+ cmd = "lumen diff"
150
+ window_name = "diff"
151
+
152
+ # 设置状态栏提示
153
+ status_cmd = (
154
+ f"tmux set-option -t {AGP_TMUX_SESSION}:{window_name} status-format "
155
+ f'"#[fg=green]Ctrl+b,n#[default] 返回 | '
156
+ f'Ctrl+b,d#[default] 关闭 | lumen: git diff"'
157
+ )
158
+ subprocess.run(status_cmd, shell=True, capture_output=True)
159
+
160
+ # 创建新窗口并执行 lumen
161
+ subprocess.run(f"tmux new-window -t {AGP_TMUX_SESSION} -n '{window_name}'", capture_output=True)
162
+ subprocess.run(
163
+ f"tmux send-keys -t {AGP_TMUX_SESSION}:{window_name} 'cd {cwd}' C-m", capture_output=True
164
+ )
165
+ subprocess.run(
166
+ f"tmux send-keys -t {AGP_TMUX_SESSION}:{window_name} '{cmd}' C-m", capture_output=True
167
+ )
168
+
169
+ return {
170
+ "success": True,
171
+ "message": f"✅ diff 面板已创建: {window_name}",
172
+ "details": {
173
+ "window": window_name,
174
+ "command": cmd,
175
+ "shortcuts": {
176
+ "next_window": "Ctrl+b, n",
177
+ "close_window": "Ctrl+b, d",
178
+ "attach_tmux": "tmux attach -t " + AGP_TMUX_SESSION,
179
+ },
180
+ },
181
+ }
182
+
183
+
184
+ async def _cmd_status() -> Dict[str, Any]:
185
+ """执行 /status 命令"""
186
+ # 检查端口
187
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
188
+ sock.settimeout(1)
189
+ try:
190
+ sock.connect((AGP_HOST, AGP_PORT))
191
+ running = True
192
+ except socket.error:
193
+ running = False
194
+ finally:
195
+ sock.close()
196
+
197
+ if running:
198
+ # 获取详细状态
199
+ import websockets
200
+ import asyncio
201
+ import json
202
+
203
+ async def get_status():
204
+ async with websockets.connect(
205
+ f"ws://{AGP_HOST}:{AGP_PORT}", open_timeout=2, close_timeout=2
206
+ ) as ws:
207
+ await ws.send(json.dumps({"action": "status"}))
208
+ return json.loads(await asyncio.wait_for(ws.recv(), timeout=2))
209
+
210
+ try:
211
+ status = asyncio.run(get_status())
212
+ return {
213
+ "success": True,
214
+ "message": "✅ AGP 守护进程正在运行",
215
+ "details": {
216
+ "status": status.get("status"),
217
+ "sessions": status.get("session_count", 0),
218
+ "connections": status.get("connections", 0),
219
+ },
220
+ }
221
+ except Exception:
222
+ return {"success": True, "message": "✅ AGP 守护进程正在运行(端口已开放)"}
223
+ else:
224
+ return {"success": False, "error": "AGP 守护进程未运行", "message": "请运行: agp start"}
225
+
226
+
227
+ async def _cmd_logs(args: list) -> Dict[str, Any]:
228
+ """执行 /logs 命令"""
229
+ if not args:
230
+ return {"success": False, "error": "缺少日志文件路径", "message": "用法: /logs <log_file>"}
231
+
232
+ log_file = args[0]
233
+
234
+ if not os.path.exists(log_file):
235
+ return {
236
+ "success": False,
237
+ "error": f"文件不存在: {log_file}",
238
+ "message": "请检查日志文件路径",
239
+ }
240
+
241
+ # 创建日志监控窗口
242
+ window_name = f"logs:{os.path.basename(log_file)}"
243
+
244
+ status_cmd = (
245
+ f"tmux set-option -t {AGP_TMUX_SESSION}:{window_name} status-format "
246
+ f'"#[fg=yellow]tail -f {os.path.basename(log_file)}#[default] | Ctrl+b,d 关闭"'
247
+ )
248
+ subprocess.run(status_cmd, shell=True, capture_output=True)
249
+
250
+ subprocess.run(f"tmux new-window -t {AGP_TMUX_SESSION} -n '{window_name}'", capture_output=True)
251
+ subprocess.run(
252
+ f"tmux send-keys -t {AGP_TMUX_SESSION}:{window_name} 'tail -f {log_file}' C-m",
253
+ capture_output=True,
254
+ )
255
+
256
+ return {
257
+ "success": True,
258
+ "message": f"✅ 日志监控已启动: {log_file}",
259
+ "details": {"window": window_name, "shortcuts": {"close_window": "Ctrl+b, d"}},
260
+ }
261
+
262
+
263
+ async def _cmd_interactive(args: list) -> Dict[str, Any]:
264
+ """执行 /interactive 命令"""
265
+ command = args[0] if args else None
266
+
267
+ window_name = "interactive"
268
+
269
+ status_cmd = (
270
+ f"tmux set-option -t {AGP_TMUX_SESSION}:{window_name} status-format "
271
+ f'"#[fg=cyan]交互式终端#[default] | Ctrl+b,d 关闭 | 输入 exit 退出"'
272
+ )
273
+ subprocess.run(status_cmd, shell=True, capture_output=True)
274
+
275
+ subprocess.run(f"tmux new-window -t {AGP_TMUX_SESSION} -n '{window_name}'", capture_output=True)
276
+
277
+ if command:
278
+ subprocess.run(
279
+ f"tmux send-keys -t {AGP_TMUX_SESSION}:{window_name} '{command}' C-m",
280
+ capture_output=True,
281
+ )
282
+
283
+ return {
284
+ "success": True,
285
+ "message": "✅ 交互式终端已创建",
286
+ "details": {
287
+ "window": window_name,
288
+ "command": command,
289
+ "shortcuts": {"close_window": "Ctrl+b, d", "send_exit": "输入 exit 然后回车"},
290
+ },
291
+ }
292
+
293
+
294
+ async def _cmd_sessions() -> Dict[str, Any]:
295
+ """执行 /sessions 命令"""
296
+ result = subprocess.run(
297
+ ["tmux", "list-sessions", "-F", "#{session_name}"], capture_output=True, text=True
298
+ )
299
+
300
+ if result.returncode == 0 and result.stdout:
301
+ sessions = result.stdout.strip().split("\n")
302
+ return {
303
+ "success": True,
304
+ "message": "✅ tmux 会话列表",
305
+ "details": {"sessions": sessions, "current": AGP_TMUX_SESSION in sessions},
306
+ }
307
+ else:
308
+ return {"success": True, "message": "暂无 tmux 会话", "details": {"sessions": []}}
309
+
310
+
311
+ # ============================================================================
312
+ # 辅助函数
313
+ # ============================================================================
314
+
315
+
316
+ def _ensure_daemon():
317
+ """确保 AGP 守护进程正在运行"""
318
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
319
+ sock.settimeout(1)
320
+ try:
321
+ sock.connect((AGP_HOST, AGP_PORT))
322
+ # 端口已开放,守护进程已在运行
323
+ return True
324
+ except socket.error:
325
+ pass
326
+ finally:
327
+ sock.close()
328
+
329
+ # 尝试启动守护进程
330
+ try:
331
+ result = subprocess.run(["agp", "start"], capture_output=True, timeout=5)
332
+ return result.returncode == 0
333
+ except Exception:
334
+ return False
335
+
336
+
337
+ # 导出插件类
338
+ plugin = AGPPlugin
package/index.js ADDED
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Agent Ghost Panel Plugin for OpenCode
3
+ *
4
+ * 这个插件将 AGP 功能集成到 OpenCode 中。
5
+ * 支持的命令:
6
+ * - /diff - 在 tmux 新窗口显示 git diff
7
+ * - /logs - 监控日志文件
8
+ * - /interactive - 交互式终端
9
+ * - /status - 查看 AGP 状态
10
+ * - /sessions - 列出 tmux 会话
11
+ */
12
+
13
+ import { tool } from "@opencode-ai/plugin";
14
+ import { spawn } from "child_process";
15
+
16
+ // AGP 配置
17
+ const AGP_PORT = process.env.AGP_PORT || "8765";
18
+ const AGP_HOST = process.env.AGP_HOST || "127.0.0.1";
19
+
20
+ const z = tool.schema;
21
+
22
+ /**
23
+ * 执行 AGP 命令
24
+ */
25
+ function executeAgp(args) {
26
+ return new Promise((resolve, reject) => {
27
+ const proc = spawn("agp", args, {
28
+ cwd: process.cwd(),
29
+ env: { ...process.env, AGP_PORT, AGP_HOST }
30
+ });
31
+
32
+ let stdout = "";
33
+ let stderr = "";
34
+
35
+ proc.stdout.on("data", (data) => {
36
+ stdout += data.toString();
37
+ });
38
+
39
+ proc.stderr.on("data", (data) => {
40
+ stderr += data.toString();
41
+ });
42
+
43
+ proc.on("close", (code) => {
44
+ if (code === 0) {
45
+ resolve(stdout);
46
+ } else {
47
+ reject(new Error(stderr || `Exit code: ${code}`));
48
+ }
49
+ });
50
+
51
+ proc.on("error", (error) => {
52
+ reject(error);
53
+ });
54
+ });
55
+ }
56
+
57
+ // 定义 AGP 工具
58
+ export const agpDiff = tool({
59
+ description: "在 tmux 新窗口显示 git diff(带语法高亮)",
60
+ args: {
61
+ file: z.string().optional().describe("文件路径(可选,默认当前目录)")
62
+ },
63
+ execute: async (args) => {
64
+ try {
65
+ const fileArg = args.file ? ` --file ${args.file}` : "";
66
+ const result = await executeAgp(["diff" + fileArg]);
67
+ return `✅ ${result}`;
68
+ } catch (error) {
69
+ return `❌ 执行失败: ${error}`;
70
+ }
71
+ }
72
+ });
73
+
74
+ export const agpLogs = tool({
75
+ description: "实时监控日志文件",
76
+ args: {
77
+ file: z.string().describe("日志文件路径")
78
+ },
79
+ execute: async (args) => {
80
+ try {
81
+ const result = await executeAgp(["logs", args.file]);
82
+ return `✅ ${result}`;
83
+ } catch (error) {
84
+ return `❌ 执行失败: ${error}`;
85
+ }
86
+ }
87
+ });
88
+
89
+ export const agpInteractive = tool({
90
+ description: "打开交互式终端(用于 ssh、sudo 等需要用户输入的命令)",
91
+ args: {
92
+ command: z.string().optional().describe("初始命令(可选)")
93
+ },
94
+ execute: async (args) => {
95
+ try {
96
+ const cmdArg = args.command ? ` ${args.command}` : "";
97
+ const result = await executeAgp(["interactive" + cmdArg]);
98
+ return `✅ ${result}`;
99
+ } catch (error) {
100
+ return `❌ 执行失败: ${error}`;
101
+ }
102
+ }
103
+ });
104
+
105
+ export const agpStatus = tool({
106
+ description: "查看 AGP 守护进程状态",
107
+ args: {},
108
+ execute: async () => {
109
+ try {
110
+ const result = await executeAgp(["status"]);
111
+ return result;
112
+ } catch (error) {
113
+ return `❌ AGP 未运行。请先运行: agp start`;
114
+ }
115
+ }
116
+ });
117
+
118
+ export const agpSessions = tool({
119
+ description: "列出所有 tmux 会话",
120
+ args: {},
121
+ execute: async () => {
122
+ try {
123
+ const result = await executeAgp(["sessions"]);
124
+ return result;
125
+ } catch (error) {
126
+ return `❌ 执行失败: ${error}`;
127
+ }
128
+ }
129
+ });
130
+
131
+ export const agpStart = tool({
132
+ description: "启动 AGP 守护进程",
133
+ args: {},
134
+ execute: async () => {
135
+ try {
136
+ const result = await executeAgp(["start"]);
137
+ return result;
138
+ } catch (error) {
139
+ return `❌ 启动失败: ${error}`;
140
+ }
141
+ }
142
+ });
143
+
144
+ export const agpStop = tool({
145
+ description: "停止 AGP 守护进程",
146
+ args: {},
147
+ execute: async () => {
148
+ try {
149
+ const result = await executeAgp(["stop"]);
150
+ return result;
151
+ } catch (error) {
152
+ return `❌ 停止失败: ${error}`;
153
+ }
154
+ }
155
+ });
156
+
157
+ // 导出插件
158
+ export default {
159
+ name: "agent-ghost-panel",
160
+ version: "0.2.0",
161
+ tools: {
162
+ "agp-diff": agpDiff,
163
+ "agp-logs": agpLogs,
164
+ "agp-interactive": agpInteractive,
165
+ "agp-status": agpStatus,
166
+ "agp-sessions": agpSessions,
167
+ "agp-start": agpStart,
168
+ "agp-stop": agpStop
169
+ }
170
+ };
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "opencode-agent-ghost-panel",
3
+ "version": "0.1.0",
4
+ "description": "基于 Tmux 的终端多路复用与交互增强",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "keywords": [
11
+ "tmux",
12
+ "terminal",
13
+ "multiplexer",
14
+ "ai-agent",
15
+ "opencode"
16
+ ],
17
+ "author": "Your Name",
18
+ "license": "MIT",
19
+ "engines": {
20
+ "node": ">=18.0.0"
21
+ },
22
+ "dependencies": {
23
+ "@opencode-ai/plugin": "^1.0.0"
24
+ }
25
+ }
package/plugin.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "agent-ghost-panel",
3
+ "version": "0.2.0",
4
+ "description": "基于 Tmux 的终端多路复用与交互增强",
5
+ "author": "Your Name",
6
+ "license": "MIT",
7
+ "entry": "__init__.py",
8
+ "plugin_class": "AGPOpenCodePlugin",
9
+ "capabilities": [
10
+ "commands",
11
+ "tools"
12
+ ],
13
+ "commands": [
14
+ {
15
+ "name": "diff",
16
+ "description": "在 tmux 新窗口显示 git diff(带颜色高亮)",
17
+ "usage": "/diff [file]",
18
+ "aliases": ["d"]
19
+ },
20
+ {
21
+ "name": "status",
22
+ "description": "查看 AGP 状态",
23
+ "usage": "/status",
24
+ "aliases": ["s"]
25
+ },
26
+ {
27
+ "name": "logs",
28
+ "description": "监控日志文件",
29
+ "usage": "/logs <log_file>",
30
+ "aliases": ["l"]
31
+ },
32
+ {
33
+ "name": "interactive",
34
+ "description": "打开交互式终端",
35
+ "usage": "/interactive [command]",
36
+ "aliases": ["i"]
37
+ },
38
+ {
39
+ "name": "sessions",
40
+ "description": "列出所有 tmux 会话",
41
+ "usage": "/sessions",
42
+ "aliases": ["ss"]
43
+ }
44
+ ],
45
+ "requirements": {
46
+ "python": ">=3.10",
47
+ "packages": [
48
+ "agent-ghost-pane"
49
+ ],
50
+ "system": {
51
+ "tmux": ">=2.0",
52
+ "lumen": "pip install lumen"
53
+ }
54
+ },
55
+ "configuration": {
56
+ "api_host": "127.0.0.1",
57
+ "api_port": 8765,
58
+ "tmux_session": "agp-opencode"
59
+ }
60
+ }