@jojonax/codex-copilot 1.0.0 → 1.0.1

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
@@ -12,10 +12,10 @@ PRD → Tasks → CodeX Dev → PR → AI Review → Fix → Merge → Next Task
12
12
 
13
13
  ```bash
14
14
  # Install globally
15
- npm install -g codex-copilot
15
+ npm install -g @jojonax/codex-copilot
16
16
 
17
17
  # Or run directly without installing
18
- npx codex-copilot
18
+ npx @jojonax/codex-copilot
19
19
 
20
20
  # In your project directory:
21
21
  codex-copilot init # Detect PRD, generate task queue
@@ -122,6 +122,13 @@ CodeX develops feature
122
122
  - [ ] GitHub Action for fully server-side automation
123
123
  - [ ] Support for monorepo / multi-package projects
124
124
 
125
+ ## Contributing
126
+
127
+ 1. Fork the repo
128
+ 2. Create a feature branch (`git checkout -b feat/awesome`)
129
+ 3. Commit your changes (`git commit -m 'feat: add awesome feature'`)
130
+ 4. Push and open a PR
131
+
125
132
  ## License
126
133
 
127
134
  MIT © Jonas Qin
package/bin/cli.js CHANGED
@@ -10,8 +10,7 @@
10
10
  * codex-copilot reset # 重置状态(重新开始)
11
11
  */
12
12
 
13
- import { fileURLToPath } from 'url';
14
- import { dirname, resolve } from 'path';
13
+ import { resolve } from 'path';
15
14
  import { existsSync } from 'fs';
16
15
 
17
16
  import { init } from '../src/commands/init.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jojonax/codex-copilot",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "PRD-driven automated development orchestrator for CodeX / Cursor",
5
5
  "bin": {
6
6
  "codex-copilot": "./bin/cli.js"
@@ -7,7 +7,7 @@
7
7
  * 4. 创建 .codex-copilot/ 目录结构
8
8
  */
9
9
 
10
- import { mkdirSync, writeFileSync, readFileSync, existsSync, copyFileSync } from 'fs';
10
+ import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'fs';
11
11
  import { resolve, dirname } from 'path';
12
12
  import { fileURLToPath } from 'url';
13
13
  import { execSync } from 'child_process';
@@ -6,6 +6,7 @@
6
6
 
7
7
  import { readFileSync, writeFileSync, existsSync } from 'fs';
8
8
  import { resolve } from 'path';
9
+ import { execSync } from 'child_process';
9
10
  import { log, progressBar } from '../utils/logger.js';
10
11
  import { git } from '../utils/git.js';
11
12
  import { github } from '../utils/github.js';
@@ -113,22 +114,14 @@ async function developPhase(projectDir, task, baseBranch) {
113
114
  const devPrompt = buildDevPrompt(task);
114
115
 
115
116
  // 检查是否有 CodeX CLI
116
- let codexAvailable = false;
117
- try {
118
- const { execSync } = await import('child_process');
119
- execSync('which codex', { stdio: 'pipe' });
120
- codexAvailable = true;
121
- } catch {}
117
+ const codexAvailable = isCodexAvailable();
122
118
 
123
119
  if (codexAvailable) {
124
120
  log.info('检测到 CodeX CLI,自动执行...');
125
121
  const autoRun = await confirm('自动调用 CodeX 开发?');
126
122
  if (autoRun) {
127
123
  try {
128
- const { execSync } = await import('child_process');
129
- // 将 prompt 写入临时文件
130
124
  const promptPath = resolve(projectDir, '.codex-copilot/_current_prompt.md');
131
- const { writeFileSync } = await import('fs');
132
125
  writeFileSync(promptPath, devPrompt);
133
126
  execSync(`codex -q --file .codex-copilot/_current_prompt.md`, {
134
127
  cwd: projectDir,
@@ -154,17 +147,12 @@ async function developPhase(projectDir, task, baseBranch) {
154
147
 
155
148
  // 同时将 Prompt 保存到文件,方便复制
156
149
  const promptPath = resolve(projectDir, '.codex-copilot/_current_prompt.md');
157
- const { writeFileSync: ws } = await import('fs');
158
- ws(promptPath, devPrompt);
150
+ writeFileSync(promptPath, devPrompt);
159
151
  log.dim(`Prompt 已保存到 .codex-copilot/_current_prompt.md (可直接复制文件内容)`);
160
152
  log.blank();
161
153
 
162
- // 尝试复制到剪贴板
163
- try {
164
- const { execSync } = await import('child_process');
165
- execSync(`echo '${devPrompt.replace(/'/g, "\\'")}' | pbcopy`, { stdio: 'pipe' });
166
- log.info('📋 已复制到剪贴板!直接到 CodeX 中粘贴即可');
167
- } catch {}
154
+ // 尝试复制到剪贴板(通过 stdin 传入,避免 shell 注入)
155
+ copyToClipboard(devPrompt);
168
156
 
169
157
  await ask('CodeX 开发完成后按 Enter 继续...');
170
158
  }
@@ -208,7 +196,8 @@ async function prPhase(projectDir, task, baseBranch) {
208
196
  // ──────────────────────────────────────────────
209
197
  // 阶段 3: Review 循环
210
198
  // ──────────────────────────────────────────────
211
- async function reviewLoop(projectDir, task, prInfo, { maxRounds, pollInterval, waitTimeout }) {
199
+ async function reviewLoop(projectDir, task, prInfo, { maxRounds: _maxRounds, pollInterval, waitTimeout }) {
200
+ let maxRounds = _maxRounds;
212
201
  log.step('阶段 3/4: 等待 Review');
213
202
 
214
203
  for (let round = 1; round <= maxRounds; round++) {
@@ -320,22 +309,15 @@ ${feedback}
320
309
 
321
310
  // 保存到文件并提示用户
322
311
  const promptPath = resolve(projectDir, '.codex-copilot/_current_prompt.md');
323
- const { writeFileSync } = await import('fs');
324
312
  writeFileSync(promptPath, fixPrompt);
325
313
 
326
314
  // 尝试 CodeX CLI
327
- let codexAvailable = false;
328
- try {
329
- const { execSync } = await import('child_process');
330
- execSync('which codex', { stdio: 'pipe' });
331
- codexAvailable = true;
332
- } catch {}
315
+ const codexAvailable = isCodexAvailable();
333
316
 
334
317
  if (codexAvailable) {
335
318
  const autoFix = await confirm('自动调用 CodeX 修复?');
336
319
  if (autoFix) {
337
320
  try {
338
- const { execSync } = await import('child_process');
339
321
  execSync(`codex -q --file .codex-copilot/_current_prompt.md`, {
340
322
  cwd: projectDir,
341
323
  stdio: 'inherit',
@@ -353,11 +335,7 @@ ${feedback}
353
335
  log.dim(`Review 修复 Prompt 已保存到 .codex-copilot/_current_prompt.md`);
354
336
  log.dim('请将文件内容粘贴到 CodeX 执行');
355
337
 
356
- try {
357
- const { execSync } = await import('child_process');
358
- execSync(`cat .codex-copilot/_current_prompt.md | pbcopy`, { cwd: projectDir, stdio: 'pipe' });
359
- log.info('📋 已复制到剪贴板');
360
- } catch {}
338
+ copyToClipboard(fixPrompt);
361
339
 
362
340
  await ask('CodeX 修复完成后按 Enter 继续...');
363
341
  }
@@ -411,3 +389,19 @@ ${task.acceptance.map(a => `- ${a}`).join('\n')}
411
389
  function sleep(ms) {
412
390
  return new Promise(resolve => setTimeout(resolve, ms));
413
391
  }
392
+
393
+ function isCodexAvailable() {
394
+ try {
395
+ execSync('which codex', { stdio: 'pipe' });
396
+ return true;
397
+ } catch {
398
+ return false;
399
+ }
400
+ }
401
+
402
+ function copyToClipboard(text) {
403
+ try {
404
+ execSync('pbcopy', { input: text, stdio: ['pipe', 'pipe', 'pipe'] });
405
+ log.info('📋 已复制到剪贴板');
406
+ } catch {}
407
+ }
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { readdirSync, readFileSync, statSync } from 'fs';
7
- import { resolve, basename, extname } from 'path';
7
+ import { resolve, extname } from 'path';
8
8
  import { log } from './logger.js';
9
9
 
10
10
  // PRD 文件名匹配模式(优先级由高到低)
package/src/utils/git.js CHANGED
@@ -71,10 +71,14 @@ export function commitAll(cwd, message) {
71
71
  log.dim('没有变更需要提交');
72
72
  return false;
73
73
  }
74
- exec(`git commit -m "${message}"`, cwd);
74
+ exec(`git commit -m ${shellEscape(message)}`, cwd);
75
75
  return true;
76
76
  }
77
77
 
78
+ function shellEscape(str) {
79
+ return `'${str.replace(/'/g, "'\\''")}'`
80
+ }
81
+
78
82
  /**
79
83
  * 推送分支
80
84
  */
@@ -14,6 +14,10 @@ function ghJSON(cmd, cwd) {
14
14
  return output ? JSON.parse(output) : null;
15
15
  }
16
16
 
17
+ function shellEscape(str) {
18
+ return `'${str.replace(/'/g, "'\\''")}'`
19
+ }
20
+
17
21
  /**
18
22
  * 检查 gh CLI 是否登录
19
23
  */
@@ -31,7 +35,7 @@ export function checkGhAuth() {
31
35
  */
32
36
  export function createPR(cwd, { title, body, base = 'main', head }) {
33
37
  const output = gh(
34
- `pr create --title "${title}" --body "${body}" --base ${base} --head ${head}`,
38
+ `pr create --title ${shellEscape(title)} --body ${shellEscape(body)} --base ${base} --head ${head}`,
35
39
  cwd
36
40
  );
37
41
  // 从输出中提取 PR URL 和编号