feat: add ChatGPT Desktop native support + Cursor/Codex advanced commands

- Add ChatGPT macOS Desktop adapter (status, new, send, read) via AppleScript
- Add Cursor composer, model, extract-code commands via CDP
- Add Codex model command via CDP
- Create adapter READMEs for ChatGPT (EN+ZH) and Cursor (EN+ZH)
- Fix README.md duplicate table rows (6 sites were listed twice)
- Update command count: 26 sites · 119 commands
- Bump version to 0.9.5
This commit is contained in:
jackwener committed 2026-03-18 19:40:08 +08:00
1 parent aa55c88069
commit 2afbb99660
12 files changed
+259 -12

No files matched your search

+4 -9
View File
@@ -143,25 +143,20 @@ npm install -g @jackwener/opencli@latest
## Built-in Commands
**19 sites · 80+ commands** — run `opencli list` for the live registry.
**26 sites · 119 commands** — run `opencli list` for the live registry.
| Site | Commands | Count | Mode |
|------|----------|:-----:|------|
| **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` | 18 | 🔐 Browser |
| **reddit** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 15 | 🔐 Browser |
| **antigravity** | `status` `send` `read` `new` `evaluate` | 5 | 🖥️ Desktop |
| **bbc** | `news` | 1 | 🌐 Public |
| **bilibili** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` | 11 | 🔐 Browser |
| **boss** | `search` `detail` | 2 | 🔐 Browser |
| **cursor** | `status` `send` `read` `new` `dump` `composer` `model` `extract-code` | 8 | 🖥️ Desktop |
| **codex** | `status` `send` `read` `new` `extract-diff` `model` | 6 | 🖥️ Desktop |
| **coupang** | `search` `add-to-cart` | 2 | 🔐 Browser |
| **ctrip** | `search` | 1 | 🔐 Browser |
| **cursor** | `status` `send` `read` `new` `dump` `composer` `model` | 7 | 🖥️ Desktop |
| **github** | `search` | 1 | 🌐 Public |
| **hackernews** | `top` | 1 | 🌐 Public |
| **v2ex** | `hot` `latest` `topic` `daily` `me` `notifications` | 6 | 🌐 / 🔐 |
| **xueqiu** | `feed` `hot-stock` `hot` `search` `stock` `watchlist` | 6 | 🔐 Browser |
| **antigravity** | `status` `send` `read` `new` `evaluate` | 5 | 🖥️ Desktop |
| **xiaohongshu** | `search` `notifications` `feed` `me` `user` | 5 | 🔐 Browser |
| **chatgpt** | `status` `new` `send` `read` | 4 | 🖥️ Desktop |
| **xiaoyuzhou** | `podcast` `podcast-episodes` `episode` | 3 | 🌐 Public |
| **youtube** | `search` `video` `transcript` | 3 | 🔐 Browser |
| **zhihu** | `hot` `search` `question` | 3 | 🔐 Browser |
+3 -2
View File
@@ -144,15 +144,16 @@ npm install -g @jackwener/opencli@latest
## 内置命令
**19 个站点 · 80+ 命令** — 运行 `opencli list` 查看完整注册表。
**26 个站点 · 119 命令** — 运行 `opencli list` 查看完整注册表。
| 站点 | 命令 | 数量 | 模式 |
|------|------|:----:|------|
| **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` | 18 | 🔐 浏览器 |
| **reddit** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 15 | 🔐 浏览器 |
| **antigravity** | `status` `send` `read` `new` `evaluate` | 5 | 🖥️ 桌面端 |
| **chatgpt** | `status` `new` `send` `read` | 4 | 🖥️ 桌面端 |
| **codex** | `status` `send` `read` `new` `extract-diff` `model` | 6 | 🖥️ 桌面端 |
| **cursor** | `status` `send` `read` `new` `dump` `composer` `model` | 7 | 🖥️ 桌面端 |
| **cursor** | `status` `send` `read` `new` `dump` `composer` `model` `extract-code` | 8 | 🖥️ 桌面端 |
| **bilibili** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` | 11 | 🔐 浏览器 |
| **v2ex** | `hot` `latest` `topic` `daily` `me` `notifications` | 6 | 🌐 / 🔐 |
| **xueqiu** | `feed` `hot-stock` `hot` `search` `stock` `watchlist` | 6 | 🔐 浏览器 |
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@jackwener/opencli",
"version": "0.9.4",
"version": "0.9.5",
"publishConfig": {
"access": "public"
},
+35
View File
@@ -0,0 +1,35 @@
# ChatGPT Desktop Adapter for OpenCLI
Control the **ChatGPT macOS Desktop App** directly from the terminal via native AppleScript automation. Unlike Electron-based apps (Antigravity, Codex, Cursor), ChatGPT Desktop is a native macOS application — OpenCLI drives it using `osascript` and System Events.
## Prerequisites
1. Install the official [ChatGPT Desktop App](https://openai.com/chatgpt/mac/) from OpenAI.
2. Grant **Accessibility permissions** to your terminal app (Terminal / iTerm / Warp) in **System Settings → Privacy & Security → Accessibility**. This is required for System Events keystroke simulation.
## Setup
No extra environment variables needed — the adapter uses `osascript` directly.
## Commands
### Diagnostics
- `opencli chatgpt status`: Check if the ChatGPT app is currently running.
### Chat Manipulation
- `opencli chatgpt new`: Activate ChatGPT and press `Cmd+N` to start a new conversation.
- `opencli chatgpt send "message"`: Copy your message to clipboard, activate ChatGPT, paste, and submit.
- `opencli chatgpt read`: Copy the last AI response via `Cmd+Shift+C` and return it as text.
## How It Works
Unlike CDP-based adapters, this adapter:
- Uses `osascript` to send AppleScript commands to System Events
- Leverages `pbcopy`/`pbpaste` for clipboard-based text transfer
- Requires no remote debugging port — works with the stock app
## Limitations
- macOS only (AppleScript dependency)
- Requires Accessibility permissions for keystroke simulation
- `read` command copies the last response — earlier messages need manual scroll
+35
View File
@@ -0,0 +1,35 @@
# ChatGPT 桌面端适配器
通过原生 AppleScript 自动化,在终端中直接控制 **ChatGPT macOS 桌面应用**。与基于 Electron 的应用(Antigravity、Codex、Cursor)不同,ChatGPT Desktop 是原生 macOS 应用 — OpenCLI 使用 `osascript` 和 System Events 来驱动它。
## 前置条件
1. 安装官方 [ChatGPT Desktop App](https://openai.com/chatgpt/mac/)。
2. 在 **系统设置 → 隐私与安全性 → 辅助功能** 中为终端应用(Terminal / iTerm / Warp)授予 **辅助功能权限**。这是 System Events 按键模拟所必需的。
## 配置
无需额外环境变量 — 适配器直接使用 `osascript`。
## 命令
### 诊断
- `opencli chatgpt status`:检查 ChatGPT 应用是否在运行。
### 对话操作
- `opencli chatgpt new`:激活 ChatGPT 并按 `Cmd+N` 开始新对话。
- `opencli chatgpt send "消息"`:将消息复制到剪贴板,激活 ChatGPT,粘贴并提交。
- `opencli chatgpt read`:通过 `Cmd+Shift+C` 复制最后一条 AI 回复并返回文本。
## 工作原理
与基于 CDP 的适配器不同,此适配器:
- 使用 `osascript` 向 System Events 发送 AppleScript 命令
- 利用 `pbcopy`/`pbpaste` 进行基于剪贴板的文本传输
- 无需远程调试端口 — 直接与原生应用交互
## 限制
- 仅支持 macOS(AppleScript 依赖)
- 需要辅助功能权限以模拟按键
- `read` 命令复制最后一条回复 — 更早的消息需要手动滚动
+24
View File
@@ -0,0 +1,24 @@
import { execSync } from 'node:child_process';
import { cli, Strategy } from '../../registry.js';
import type { IPage } from '../../types.js';
export const newCommand = cli({
site: 'chatgpt',
name: 'new',
description: 'Open a new chat in ChatGPT Desktop App',
domain: 'localhost',
strategy: Strategy.PUBLIC,
browser: false,
args: [],
columns: ['Status'],
func: async (page: IPage | null) => {
try {
execSync("osascript -e 'tell application \"ChatGPT\" to activate'");
execSync("osascript -e 'delay 0.5'");
execSync("osascript -e 'tell application \"System Events\" to keystroke \"n\" using command down'");
return [{ Status: 'Success' }];
} catch (err: any) {
return [{ Status: "Error: " + err.message }];
}
},
});
+32
View File
@@ -0,0 +1,32 @@
import { execSync } from 'node:child_process';
import { cli, Strategy } from '../../registry.js';
import type { IPage } from '../../types.js';
export const readCommand = cli({
site: 'chatgpt',
name: 'read',
description: 'Copy the most recent ChatGPT Desktop App response to clipboard and read it',
domain: 'localhost',
strategy: Strategy.PUBLIC,
browser: false,
args: [],
columns: ['Role', 'Text'],
func: async (page: IPage | null) => {
try {
execSync("osascript -e 'tell application \"ChatGPT\" to activate'");
execSync("osascript -e 'delay 0.5'");
execSync("osascript -e 'tell application \"System Events\" to keystroke \"c\" using {command down, shift down}'");
execSync("osascript -e 'delay 0.3'");
const result = execSync('pbpaste', { encoding: 'utf-8' }).trim();
if (!result) {
return [{ Role: 'System', Text: 'No text was copied. Is there a response in the chat?' }];
}
return [{ Role: 'Assistant', Text: result }];
} catch (err: any) {
throw new Error("Failed to read from ChatGPT: " + err.message);
}
},
});
+36
View File
@@ -0,0 +1,36 @@
import { execSync, spawnSync } from 'node:child_process';
import { cli, Strategy } from '../../registry.js';
import type { IPage } from '../../types.js';
export const sendCommand = cli({
site: 'chatgpt',
name: 'send',
description: 'Send a message to the active ChatGPT Desktop App window',
domain: 'localhost',
strategy: Strategy.PUBLIC,
browser: false,
args: [{ name: 'text', required: true, positional: true, help: 'Message to send' }],
columns: ['Status'],
func: async (page: IPage | null, kwargs: any) => {
const text = kwargs.text as string;
try {
spawnSync('pbcopy', { input: text });
execSync("osascript -e 'tell application \"ChatGPT\" to activate'");
execSync("osascript -e 'delay 0.5'");
const cmd = "osascript " +
"-e 'tell application \"System Events\"' " +
"-e 'keystroke \"v\" using command down' " +
"-e 'delay 0.2' " +
"-e 'keystroke return' " +
"-e 'end tell'";
execSync(cmd);
return [{ Status: 'Success' }];
} catch (err: any) {
return [{ Status: "Error: " + err.message }];
}
},
});
+22
View File
@@ -0,0 +1,22 @@
import { execSync } from 'node:child_process';
import { cli, Strategy } from '../../registry.js';
import type { IPage } from '../../types.js';
export const statusCommand = cli({
site: 'chatgpt',
name: 'status',
description: 'Check if ChatGPT Desktop App is running natively on macOS',
domain: 'localhost',
strategy: Strategy.PUBLIC,
browser: false,
args: [],
columns: ['Status'],
func: async (page: IPage | null) => {
try {
const output = execSync("osascript -e 'application \"ChatGPT\" is running'", { encoding: 'utf-8' }).trim();
return [{ Status: output === 'true' ? 'Running' : 'Stopped' }];
} catch {
return [{ Status: 'Error querying application state' }];
}
},
});
+1
View File
@@ -31,3 +31,4 @@ export OPENCLI_CODEX_CDP_ENDPOINT="http://127.0.0.1:9222"
- *Pro-tip*: You can trigger internal shortcuts by sending them, e.g., `opencli codex send "/review"` or `opencli codex send "$imagegen draw a cat"`.
- `opencli codex read`: Extracts the entire current thread history and AI reasoning logs into readable text.
- `opencli codex extract-diff`: Automatically scrapes any visual Patch chunks and Code Diffs the AI generated inside the review UI.
- `opencli codex model`: Get the currently active AI model.
+33
View File
@@ -0,0 +1,33 @@
# Cursor Adapter for OpenCLI
Control the **Cursor IDE** from the terminal via Chrome DevTools Protocol (CDP). Since Cursor is built on Electron (VS Code fork), OpenCLI can drive its internal UI, automate Composer interactions, and manipulate chat sessions.
## Prerequisites
1. Install [Cursor](https://cursor.sh/).
2. Launch it with the remote debugging port:
```bash
/Applications/Cursor.app/Contents/MacOS/Cursor --remote-debugging-port=9226
```
## Setup
```bash
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9226"
```
## Commands
### Diagnostics
- `opencli cursor status`: Check CDP connection status.
- `opencli cursor dump`: Dump the full DOM and Accessibility snapshot to `/tmp/cursor-dom.html` and `/tmp/cursor-snapshot.json`.
### Chat Manipulation
- `opencli cursor new`: Press `Cmd+N` to start a new file/tab.
- `opencli cursor send "message"`: Inject text into the active Composer/Chat input and submit.
- `opencli cursor read`: Extract the full conversation history from the active chat panel.
### AI Features
- `opencli cursor composer "prompt"`: Open the Composer panel (`Cmd+I`) and send a prompt for inline AI editing.
- `opencli cursor model`: Get the currently active AI model (e.g., `claude-4.5-sonnet`).
- `opencli cursor extract-code`: Extract all code blocks from the current conversation.
+33
View File
@@ -0,0 +1,33 @@
# Cursor 适配器
通过 Chrome DevTools Protocol (CDP) 在终端中控制 **Cursor IDE**。由于 Cursor 基于 Electron(VS Code 分支),OpenCLI 可以驱动其内部 UI,自动化 Composer 交互,操控聊天会话。
## 前置条件
1. 安装 [Cursor](https://cursor.sh/)。
2. 通过远程调试端口启动:
```bash
/Applications/Cursor.app/Contents/MacOS/Cursor --remote-debugging-port=9226
```
## 配置
```bash
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9226"
```
## 命令
### 诊断
- `opencli cursor status`:检查 CDP 连接状态。
- `opencli cursor dump`:导出完整 DOM 和 Accessibility 快照到 `/tmp/cursor-dom.html` 和 `/tmp/cursor-snapshot.json`。
### 对话操作
- `opencli cursor new`:按 `Cmd+N` 创建新文件/标签。
- `opencli cursor send "消息"`:将文本注入活跃的 Composer/Chat 输入框并提交。
- `opencli cursor read`:提取当前聊天面板的完整对话历史。
### AI 功能
- `opencli cursor composer "提示词"`:打开 Composer 面板(`Cmd+I`)并发送提示词进行内联 AI 编辑。
- `opencli cursor model`:获取当前活跃的 AI 模型(如 `claude-4.5-sonnet`)。
- `opencli cursor extract-code`:从当前对话中提取所有代码块。