ronds_ai 0.1.13 → 0.1.17

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 CHANGED
@@ -1,4 +1,4 @@
1
- # ronds_ai
1
+ # ronds_ai
2
2
 
3
3
  `ronds_ai` 是一个命令行工具,主要用于两类事情:
4
4
 
@@ -121,11 +121,12 @@ npx ronds_ai@latest record cursor
121
121
 
122
122
  行为说明:
123
123
 
124
- - 从 `stdin` 读取一段 JSON
125
- - 根据来源提取文件路径、变更内容、增删行数、仓库信息、worker_id
126
- - 组装事件后通过 HTTP POST 上报
127
- - 成功时输出一行 JSON
128
- - 失败时会把事件写入本地失败日志,并输出保存位置
124
+ - 从 `stdin` 读取一段 JSON
125
+ - 根据来源提取文件路径、变更内容、增删行数、仓库信息、worker_id
126
+ - 组装事件后通过 HTTP POST 上报
127
+ - Claude / Cursor 成功时输出一行 JSON
128
+ - Claude / Cursor 失败时会把事件写入本地失败日志,并输出保存位置
129
+ - Codex 作为 `PostToolUse` hook 调用时,标准输出固定为 Codex hook command output schema,避免触发 `invalid post-tool-use JSON output`
129
130
 
130
131
  成功输出示例:
131
132
 
@@ -148,7 +149,7 @@ npx ronds_ai@latest record cursor
148
149
  目前支持的 hook 事件:
149
150
 
150
151
  - Claude: `PostToolUse`
151
- - Codex: `UserPromptSubmit` + `Stop`(两阶段处理)
152
+ - Codex: `PostToolUse`(`apply_patch` 编辑后采集)
152
153
  - Cursor: `afterFileEdit`
153
154
 
154
155
  其中 Claude 仅处理这些工具产生的事件:
@@ -157,7 +158,13 @@ npx ronds_ai@latest record cursor
157
158
  - `Edit`
158
159
  - `MultiEdit`
159
160
 
160
- Codex 使用 `UserPromptSubmit` `Stop` 两个 hook 阶段:前者保存当前 turn 的快照,后者基于快照计算变更事件;失败事件同样写入 `~/.ronds_ai/failed-events`。
161
+ Codex 使用 `PostToolUse` hook,在 `apply_patch` 执行后直接解析本次补丁内容并生成变更事件;失败事件同样写入 `~/.ronds_ai/failed-events`。
162
+
163
+ Codex 输出示例:
164
+
165
+ ```json
166
+ {"continue":true,"suppressOutput":true,"hookSpecificOutput":{"hookEventName":"PostToolUse"}}
167
+ ```
161
168
 
162
169
  ### `doctor`
163
170
 
@@ -196,7 +203,8 @@ Claude 会检查:
196
203
 
197
204
  Codex 会检查:
198
205
 
199
- - `.codex/hooks.json`
206
+ - Windows: `C:\ProgramData\OpenAI\Codex\requirements.toml`
207
+ - Linux / macOS: `/etc/codex/requirements.toml`
200
208
 
201
209
  Cursor 会检查:
202
210
 
@@ -204,33 +212,44 @@ Cursor 会检查:
204
212
 
205
213
  ### `hooks deploy`
206
214
 
207
- 在当前项目目录生成或更新 Claude / Codex / Cursor 的 hook 配置。
215
+ 在当前项目目录或用户目录生成/更新 Claude / Codex / Cursor 的 hook 配置。
208
216
 
209
217
  ```bash
210
- ronds_ai hooks deploy
218
+ ronds_ai hooks deploy [--scope project|user]
211
219
  ```
212
220
 
213
221
  示例:
214
222
 
215
223
  ```bash
216
224
  npx ronds_ai@latest hooks deploy
225
+ npx ronds_ai@latest hooks deploy --scope user
217
226
  ```
218
227
 
219
- 这个命令会做的事情:
228
+ 默认 scope 为 `project`(项目级部署),行为:
220
229
 
221
- - `.cursor/hooks.json` 中确保存在 `npx ronds_ai@latest record cursor`
222
- - `.claude/settings.json` 中确保存在 `npx ronds_ai@latest record claude`
223
- - `.codex/hooks.json` 中确保存在 `npx ronds_ai@latest record codex`(`UserPromptSubmit` + `Stop` 两个 hook)
224
- - `.codex/config.toml` 中确保存在 `[features] codex_hooks = true`,启用 Codex hooks
225
- - 清理旧版 hook 脚本文件
226
- - 如果存在 `.claude/settings.local.json`,会移除其中由本工具管理的旧 hook,避免重复触发
227
- - 所有工具的失败事件统一写入 `~/.ronds_ai/failed-events`
230
+ - 写入或更新 `.cursor/hooks.json`
231
+ - 写入或更新 `.claude/settings.json`
232
+ - 清理项目内旧版 Cursor、Claude、Codex hook 脚本
233
+ - 跳过 Codex 项目级配置部署,并在输出中说明原因
228
234
 
229
- 输出是一个 JSON,对应本次操作中:
235
+ `--scope user`(用户级部署),行为:
230
236
 
237
+ - 写入或更新用户级 Cursor hook 配置
238
+ - 写入或更新用户级 Claude hook 配置
239
+ - 写入或更新系统级 `requirements.toml`(Windows: `C:\ProgramData\OpenAI\Codex\requirements.toml`,Linux / macOS: `/etc/codex/requirements.toml`),包含 `[features] hooks = true`、`[hooks]` 托管目录配置以及 `PostToolUse` 的 `apply_patch` hook
240
+ - 清理用户目录中的旧版 hook 脚本文件
241
+
242
+ Codex 推荐使用 `--scope user`,因为项目级 `.codex` 配置在未被用户显式信任的项目中会被 Codex 忽略。
243
+
244
+ 输出是一个 JSON,包含:
245
+
246
+ - `scope`: 本次部署的 scope
247
+ - `targetDir`: 命令执行时的项目目录
248
+ - `configRoot`: 实际写入配置的根目录
231
249
  - `createdFiles`
232
250
  - `updatedFiles`
233
251
  - `removedFiles`
252
+ - `skipped`: 被跳过的工具及原因(仅在 project scope 下出现)
234
253
 
235
254
  ### `skills install`
236
255
 
@@ -284,7 +303,7 @@ npx ronds_ai@latest skills install demo-skill --tool codex,cursor --scope projec
284
303
  - `HOOK_REPORT_TIMEOUT_MS`: 请求超时时间,默认 `10000`
285
304
  - `HOOK_REPORT_TOKEN`: 如果设置,会以 `Authorization: Bearer <token>` 发送
286
305
  - `HOOK_REPORT_HEADERS`: 额外请求头,要求是 JSON 字符串
287
- - `HOOK_REQUEST_DRY_RUN=1`: 不发请求,只把事件打印到标准输出
306
+ - `HOOK_REQUEST_DRY_RUN=1`: 不发请求。Claude / Cursor 会把事件打印到标准输出;Codex 仍输出合法的 PostToolUse hook command output schema
288
307
 
289
308
  默认上报地址:
290
309
 
@@ -322,3 +341,4 @@ https://aihub.ronds.com/api/api/v1/ai-code-events
322
341
  - `record` 和 `doctor` 目前支持 `claude`、`codex` 与 `cursor`
323
342
  - `skills install` 支持 `claude`、`codex`、`cursor`
324
343
  - 不支持的命令或参数会直接报错,并把错误写入 CLI 错误日志
344
+
package/bin/ronds_ai.js CHANGED
@@ -65,7 +65,7 @@ function printUsage() {
65
65
  ' ronds_ai record <tool>',
66
66
  ' ronds_ai check record',
67
67
  ' ronds_ai doctor <tool>',
68
- ' ronds_ai hooks deploy',
68
+ ' ronds_ai hooks deploy [--scope project|user] [--tool cursor|claude|codex]',
69
69
  ' ronds_ai skills install <name> [--tool claude,codex,cursor] [--scope project|global] [--project-dir <path>] [--force]',
70
70
  '',
71
71
  'Supported tools:',
@@ -80,6 +80,9 @@ function printUsage() {
80
80
  ' npx ronds_ai@latest doctor claude',
81
81
  ' npx ronds_ai@latest doctor cursor',
82
82
  ' npx ronds_ai@latest hooks deploy',
83
+ ' npx ronds_ai@latest hooks deploy --scope user',
84
+ ' npx ronds_ai@latest hooks deploy --tool cursor',
85
+ ' npx ronds_ai@latest hooks deploy --tool claude --scope user',
83
86
  ' npx ronds_ai@latest skills install demo-skill',
84
87
  ' npx ronds_ai@latest skills install demo-skill --tool claude --scope global',
85
88
  ' npx ronds_ai@latest skills install demo-skill --tool codex,cursor --scope project',
@@ -88,13 +91,8 @@ function printUsage() {
88
91
  }
89
92
 
90
93
  async function runHooksCommand(args) {
91
- const [action] = args;
92
-
93
- if (action !== 'deploy') {
94
- throw new Error('Unsupported hooks command');
95
- }
96
-
97
- const result = deployHooks(process.cwd());
94
+ const options = parseHooksDeployArgs(args);
95
+ const result = deployHooks(process.cwd(), options);
98
96
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
99
97
  }
100
98
 
@@ -186,6 +184,60 @@ function parseSkillsInstallArgs(args) {
186
184
  };
187
185
  }
188
186
 
187
+ function parseHooksDeployArgs(args) {
188
+ const [action, ...rest] = args;
189
+ if (action !== 'deploy') {
190
+ throw new Error('Unsupported hooks command');
191
+ }
192
+
193
+ const options = {
194
+ scope: 'project',
195
+ tool: '',
196
+ };
197
+
198
+ for (let index = 0; index < rest.length; index += 1) {
199
+ const value = rest[index];
200
+
201
+ if (value === '--scope') {
202
+ index += 1;
203
+ options.scope = rest[index] || '';
204
+ continue;
205
+ }
206
+
207
+ if (value.startsWith('--scope=')) {
208
+ options.scope = value.slice('--scope='.length);
209
+ continue;
210
+ }
211
+
212
+ if (value === '--tool') {
213
+ index += 1;
214
+ options.tool = rest[index] || '';
215
+ continue;
216
+ }
217
+
218
+ if (value.startsWith('--tool=')) {
219
+ options.tool = value.slice('--tool='.length);
220
+ continue;
221
+ }
222
+
223
+ throw new Error(`Unsupported option: ${value}`);
224
+ }
225
+
226
+ if (!['project', 'user'].includes(options.scope)) {
227
+ throw new Error(`Unsupported hooks deploy scope: ${options.scope}`);
228
+ }
229
+
230
+ if (options.tool) {
231
+ const normalizedTool = options.tool.trim().toLowerCase();
232
+ if (!SUPPORTED_SOURCES.has(normalizedTool)) {
233
+ throw new Error(`Unsupported hooks deploy tool: ${options.tool}`);
234
+ }
235
+ options.tool = normalizedTool;
236
+ }
237
+
238
+ return options;
239
+ }
240
+
189
241
  async function runSkillsCommand(args) {
190
242
  const { runSkillsInstall } = require('../lib/skills_install');
191
243
  const [action, ...rest] = args;