@jojonax/codex-copilot 1.0.2 → 1.0.3

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/bin/cli.js CHANGED
@@ -1,31 +1,39 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * codex-copilot CLI - PRD → 自动开发 → PR → Review → 修复合并
4
+ * codex-copilot CLI - PRD → Auto Dev → PR → Review → FixMerge
5
5
  *
6
- * 用法:
7
- * codex-copilot init # 初始化项目(自动检测 PRD,生成任务)
8
- * codex-copilot run # 启动自动化开发循环
9
- * codex-copilot status # 查看当前进度
10
- * codex-copilot reset # 重置状态(重新开始)
6
+ * Usage:
7
+ * codex-copilot init # Initialize project (auto-detect PRD, generate tasks)
8
+ * codex-copilot run # Start automated development loop
9
+ * codex-copilot status # View current progress
10
+ * codex-copilot reset # Reset state (start over)
11
11
  */
12
12
 
13
- import { resolve } from 'path';
14
- import { existsSync } from 'fs';
13
+ import { resolve, dirname } from 'path';
14
+ import { existsSync, readFileSync } from 'fs';
15
+ import { fileURLToPath } from 'url';
15
16
 
16
17
  import { init } from '../src/commands/init.js';
17
18
  import { run } from '../src/commands/run.js';
18
19
  import { status } from '../src/commands/status.js';
19
20
  import { reset } from '../src/commands/reset.js';
20
21
  import { log } from '../src/utils/logger.js';
22
+ import { checkForUpdates } from '../src/utils/update-check.js';
21
23
 
22
24
  const command = process.argv[2];
23
25
  const projectDir = process.cwd();
24
26
 
27
+ // Read version from package.json
28
+ const __filename = fileURLToPath(import.meta.url);
29
+ const __dirname = dirname(__filename);
30
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf-8'));
31
+ const version = pkg.version;
32
+
25
33
  // Banner
26
34
  console.log('');
27
35
  console.log(' ╔══════════════════════════════════════════╗');
28
- console.log(' ║ 🤖 Codex-Copilot v1.0 ║');
36
+ console.log(` ║ 🤖 Codex-Copilot v${version.padEnd(18)}║`);
29
37
  console.log(' ║ PRD-Driven Auto Development ║');
30
38
  console.log(' ╚══════════════════════════════════════════╝');
31
39
  console.log('');
@@ -39,7 +47,7 @@ async function main() {
39
47
 
40
48
  case 'run':
41
49
  if (!existsSync(resolve(projectDir, '.codex-copilot/tasks.json'))) {
42
- log.error('尚未初始化,请先运行: codex-copilot init');
50
+ log.error('Not initialized. Run: codex-copilot init');
43
51
  process.exit(1);
44
52
  }
45
53
  await run(projectDir);
@@ -47,7 +55,7 @@ async function main() {
47
55
 
48
56
  case 'status':
49
57
  if (!existsSync(resolve(projectDir, '.codex-copilot/tasks.json'))) {
50
- log.error('尚未初始化,请先运行: codex-copilot init');
58
+ log.error('Not initialized. Run: codex-copilot init');
51
59
  process.exit(1);
52
60
  }
53
61
  await status(projectDir);
@@ -58,26 +66,29 @@ async function main() {
58
66
  break;
59
67
 
60
68
  default:
61
- console.log(' 用法: codex-copilot <command>');
69
+ console.log(' Usage: codex-copilot <command>');
62
70
  console.log('');
63
- console.log(' 命令:');
64
- console.log(' init 初始化项目(自动检测 PRD,生成任务队列)');
65
- console.log(' run 启动自动化开发循环');
66
- console.log(' status 查看当前任务进度');
67
- console.log(' reset 重置状态,重新开始');
71
+ console.log(' Commands:');
72
+ console.log(' init Initialize project (auto-detect PRD, generate task queue)');
73
+ console.log(' run Start automated development loop');
74
+ console.log(' status View current task progress');
75
+ console.log(' reset Reset state and start over');
68
76
  console.log('');
69
- console.log(' 工作流程:');
70
- console.log(' 1. cd 到你的项目目录');
71
- console.log(' 2. codex-copilot init (自动检测 PRD 并拆解任务)');
72
- console.log(' 3. codex-copilot run (开始自动开发循环)');
77
+ console.log(' Workflow:');
78
+ console.log(' 1. cd into your project directory');
79
+ console.log(' 2. codex-copilot init (auto-detect PRD and decompose tasks)');
80
+ console.log(' 3. codex-copilot run (start automated dev loop)');
73
81
  console.log('');
74
82
  break;
75
83
  }
76
84
  } catch (err) {
77
- log.error(`执行失败: ${err.message}`);
85
+ log.error(`Execution failed: ${err.message}`);
78
86
  if (process.env.DEBUG) console.error(err);
79
87
  process.exit(1);
80
88
  }
81
89
  }
82
90
 
91
+ // Check for updates (non-blocking, cached 24h)
92
+ checkForUpdates(version);
93
+
83
94
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jojonax/codex-copilot",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "PRD-driven automated development orchestrator for CodeX / Cursor",
5
5
  "bin": {
6
6
  "codex-copilot": "./bin/cli.js"
@@ -1,10 +1,10 @@
1
1
  /**
2
- * codex-copilot init - 初始化项目
2
+ * codex-copilot init - Initialize project
3
3
  *
4
- * 1. 自动检测 PRD 文档
5
- * 2. 让用户确认/选择 PRD
6
- * 3. 生成 CodeX 可执行的任务拆解 Prompt
7
- * 4. 创建 .codex-copilot/ 目录结构
4
+ * 1. Auto-detect PRD document
5
+ * 2. Let user confirm/select PRD
6
+ * 3. Generate CodeX-executable task decomposition prompt
7
+ * 4. Create .codex-copilot/ directory structure
8
8
  */
9
9
 
10
10
  import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'fs';
@@ -17,34 +17,34 @@ import { git } from '../utils/git.js';
17
17
  import { github } from '../utils/github.js';
18
18
 
19
19
  export async function init(projectDir) {
20
- log.title('📋 初始化 Codex-Copilot');
20
+ log.title('📋 Initializing Codex-Copilot');
21
21
  log.blank();
22
22
 
23
- // ===== 前置检查 =====
24
- log.step('检查环境...');
23
+ // ===== Pre-flight checks =====
24
+ log.step('Checking environment...');
25
25
 
26
- // 检查是否在 git 仓库中
26
+ // Check if in a git repo
27
27
  try {
28
28
  git.currentBranch(projectDir);
29
- log.info('Git 仓库 ✓');
29
+ log.info('Git repository ✓');
30
30
  } catch {
31
- log.error('当前目录不是 Git 仓库,请先 git init');
31
+ log.error('Not a Git repository. Run: git init');
32
32
  closePrompt();
33
33
  process.exit(1);
34
34
  }
35
35
 
36
- // 检查 gh CLI
36
+ // Check gh CLI
37
37
  if (!github.checkGhAuth()) {
38
- log.error('GitHub CLI 未登录,请先运行: gh auth login');
38
+ log.error('GitHub CLI not authenticated. Run: gh auth login');
39
39
  closePrompt();
40
40
  process.exit(1);
41
41
  }
42
42
  log.info('GitHub CLI ✓');
43
43
 
44
- // 检查 GitHub remote
44
+ // Check GitHub remote
45
45
  try {
46
46
  const repo = git.getRepoInfo(projectDir);
47
- log.info(`GitHub 仓库: ${repo.owner}/${repo.repo} ✓`);
47
+ log.info(`GitHub repo: ${repo.owner}/${repo.repo} ✓`);
48
48
  } catch (err) {
49
49
  log.error(err.message);
50
50
  closePrompt();
@@ -53,57 +53,57 @@ export async function init(projectDir) {
53
53
 
54
54
  log.blank();
55
55
 
56
- // ===== 检测 PRD =====
57
- log.step('扫描 PRD 文档...');
56
+ // ===== Detect PRD =====
57
+ log.step('Scanning for PRD documents...');
58
58
  const candidates = detectPRD(projectDir);
59
59
 
60
60
  let prdPath;
61
61
 
62
62
  if (candidates.length === 0) {
63
- log.warn('未自动检测到 PRD 文档');
64
- const manualPath = await ask('请输入 PRD 文件路径(相对或绝对路径):');
63
+ log.warn('No PRD document detected automatically');
64
+ const manualPath = await ask('Enter PRD file path (relative or absolute):');
65
65
  prdPath = resolve(projectDir, manualPath);
66
- // 防止路径穿越:确保 PRD 路径在项目目录内或是绝对路径
66
+ // Prevent path traversal
67
67
  if (!prdPath.startsWith(resolve(projectDir)) && !manualPath.startsWith('/')) {
68
- log.error('PRD 路径不在项目目录内');
68
+ log.error('PRD path is outside the project directory');
69
69
  closePrompt();
70
70
  process.exit(1);
71
71
  }
72
72
  if (!existsSync(prdPath)) {
73
- log.error(`文件不存在: ${prdPath}`);
73
+ log.error(`File not found: ${prdPath}`);
74
74
  closePrompt();
75
75
  process.exit(1);
76
76
  }
77
77
  } else if (candidates.length === 1) {
78
78
  prdPath = candidates[0].path;
79
- log.info(`找到 PRD: ${candidates[0].relativePath}`);
80
- const ok = await confirm('使用该文件?');
79
+ log.info(`Found PRD: ${candidates[0].relativePath}`);
80
+ const ok = await confirm('Use this file?');
81
81
  if (!ok) {
82
- const manualPath = await ask('请输入 PRD 文件路径:');
82
+ const manualPath = await ask('Enter PRD file path:');
83
83
  prdPath = resolve(projectDir, manualPath);
84
84
  }
85
85
  } else {
86
- log.info(`找到 ${candidates.length} 个候选 PRD 文件:`);
87
- const choice = await select('请选择要使用的 PRD:', candidates.map(c => ({
88
- label: `${c.relativePath} (匹配度: ${c.score})`,
86
+ log.info(`Found ${candidates.length} candidate PRD files:`);
87
+ const choice = await select('Select the PRD to use:', candidates.map(c => ({
88
+ label: `${c.relativePath} (score: ${c.score})`,
89
89
  value: c.path,
90
90
  })));
91
91
  prdPath = choice.value;
92
92
  }
93
93
 
94
- log.info(`使用 PRD: ${prdPath}`);
94
+ log.info(`Using PRD: ${prdPath}`);
95
95
  log.blank();
96
96
 
97
- // ===== 读取 PRD =====
97
+ // ===== Read PRD =====
98
98
  const prdContent = readPRD(prdPath);
99
- log.info(`PRD 大小: ${(prdContent.length / 1024).toFixed(1)} KB`);
99
+ log.info(`PRD size: ${(prdContent.length / 1024).toFixed(1)} KB`);
100
100
 
101
- // ===== 创建 .codex-copilot 目录 =====
102
- log.step('创建 .codex-copilot/ 目录...');
101
+ // ===== Create .codex-copilot directory =====
102
+ log.step('Creating .codex-copilot/ directory...');
103
103
  const copilotDir = resolve(projectDir, '.codex-copilot');
104
104
  mkdirSync(copilotDir, { recursive: true });
105
105
 
106
- // 写入配置文件
106
+ // Write config file
107
107
  const config = {
108
108
  prd_path: prdPath,
109
109
  base_branch: git.currentBranch(projectDir) || 'main',
@@ -114,7 +114,7 @@ export async function init(projectDir) {
114
114
  };
115
115
  writeFileSync(resolve(copilotDir, 'config.json'), JSON.stringify(config, null, 2));
116
116
 
117
- // 写入初始状态
117
+ // Write initial state
118
118
  const state = {
119
119
  current_task: 0,
120
120
  current_pr: null,
@@ -123,28 +123,28 @@ export async function init(projectDir) {
123
123
  };
124
124
  writeFileSync(resolve(copilotDir, 'state.json'), JSON.stringify(state, null, 2));
125
125
 
126
- // 写入 CodeX 指令模板
127
- const instructions = `# Codex-Copilot 开发指令
126
+ // Write CodeX instruction template
127
+ const instructions = `# Codex-Copilot Development Instructions
128
128
 
129
- ## 角色
130
- 你是一个高效的自动开发 Agent,负责按照任务描述完成功能开发。
129
+ ## Role
130
+ You are an efficient automated development agent responsible for completing feature development according to task descriptions.
131
131
 
132
- ## 规则
133
- 1. **严格遵循项目技术栈**:使用项目已有的框架、工具和代码风格
134
- 2. **自测优先**:开发完成前确保代码可以编译/运行
135
- 3. **Git 规范**:提交信息格式 \`feat(task-N): 简要描述\` \`fix(task-N): 简要描述\`
136
- 4. **不要修改无关文件**:只修改当前任务需要的文件
137
- 5. **完成后执行 git commit**:\`git add -A && git commit -m "..."\`
132
+ ## Rules
133
+ 1. **Follow the project tech stack**: Use the existing frameworks, tools, and code style
134
+ 2. **Test first**: Ensure code compiles/runs before finishing
135
+ 3. **Git conventions**: Commit message format \`feat(task-N): brief description\` or \`fix(task-N): brief description\`
136
+ 4. **Don't modify unrelated files**: Only change files required by the current task
137
+ 5. **Commit when done**: \`git add -A && git commit -m "..."\`
138
138
 
139
- ## 修复 Review 时的规则
140
- 1. 逐条阅读 Review 意见
141
- 2. 区分必须修复 vs 建议性意见
142
- 3. 对于不认同的意见,在 commit message 中说明原因
143
- 4. 修复后确保不引入新问题
139
+ ## Rules for fixing reviews
140
+ 1. Read each review comment carefully
141
+ 2. Distinguish between must-fix vs. suggestions
142
+ 3. If you disagree with a comment, explain why in the commit message
143
+ 4. Ensure fixes don't introduce new issues
144
144
  `;
145
145
  writeFileSync(resolve(copilotDir, 'codex-instructions.md'), instructions);
146
146
 
147
- // 添加 .gitignore
147
+ // Add .gitignore entries
148
148
  const gitignorePath = resolve(projectDir, '.gitignore');
149
149
  const gitignoreEntry = '\n# Codex-Copilot state\n.codex-copilot/state.json\n';
150
150
  if (existsSync(gitignorePath)) {
@@ -154,49 +154,49 @@ export async function init(projectDir) {
154
154
  }
155
155
  }
156
156
 
157
- log.info('.codex-copilot/ 目录已创建');
157
+ log.info('.codex-copilot/ directory created');
158
158
  log.blank();
159
159
 
160
- // ===== 生成任务拆解 Prompt =====
161
- log.step('生成任务拆解 Prompt...');
160
+ // ===== Generate task decomposition prompt =====
161
+ log.step('Generating task decomposition prompt...');
162
162
 
163
163
  const parsePrompt = buildParsePrompt(prdContent, copilotDir);
164
164
  const promptPath = resolve(copilotDir, 'parse-prd-prompt.md');
165
165
  writeFileSync(promptPath, parsePrompt);
166
166
 
167
- log.info(`任务拆解 Prompt 已保存到: .codex-copilot/parse-prd-prompt.md`);
167
+ log.info('Task decomposition prompt saved to: .codex-copilot/parse-prd-prompt.md');
168
168
  log.blank();
169
169
 
170
- // ===== 提示用户下一步 =====
171
- log.title('✅ 初始化完成!');
170
+ // ===== Guide user to next steps =====
171
+ log.title('✅ Initialization complete!');
172
172
  log.blank();
173
- log.info('接下来请执行以下步骤:');
173
+ log.info('Next steps:');
174
174
  log.blank();
175
175
  console.log(' ┌───────────────────────────────────────────────────┐');
176
- console.log(' │ 1. 打开 CodeX 桌面版 │');
177
- console.log(' │ 2. 将以下文件内容粘贴给 CodeX 执行: │');
176
+ console.log(' │ 1. Open CodeX Desktop │');
177
+ console.log(' │ 2. Paste the following file content into CodeX: │');
178
178
  console.log(' │ .codex-copilot/parse-prd-prompt.md │');
179
- console.log(' │ 3. CodeX 会生成 .codex-copilot/tasks.json │');
180
- console.log(' │ 4. 确认任务列表后运行: │');
179
+ console.log(' │ 3. CodeX will generate .codex-copilot/tasks.json │');
180
+ console.log(' │ 4. Confirm the task list, then run: │');
181
181
  console.log(' │ codex-copilot run │');
182
182
  console.log(' └───────────────────────────────────────────────────┘');
183
183
  log.blank();
184
184
 
185
- // 询问是否尝试自动拆解(如果 codex CLI 可用)
185
+ // Ask if user wants to auto-decompose (if codex CLI is available)
186
186
  const hasCodexCLI = checkCodexCLI();
187
187
  if (hasCodexCLI) {
188
- log.info('检测到 CodeX CLI 可用!');
189
- const autoparse = await confirm('是否自动调用 CodeX 拆解 PRD');
188
+ log.info('CodeX CLI detected!');
189
+ const autoparse = await confirm('Auto-invoke CodeX to decompose PRD?');
190
190
  if (autoparse) {
191
- log.step('调用 CodeX CLI 拆解 PRD...');
191
+ log.step('Invoking CodeX CLI to decompose PRD...');
192
192
  try {
193
- execSync(`codex -q --file .codex-copilot/parse-prd-prompt.md`, {
193
+ execSync(`cat .codex-copilot/parse-prd-prompt.md | codex exec --full-auto -`, {
194
194
  cwd: projectDir,
195
195
  stdio: 'inherit',
196
196
  });
197
- log.info('CodeX 拆解完成!');
197
+ log.info('CodeX decomposition complete!');
198
198
  } catch {
199
- log.warn('CodeX CLI 调用失败,请手动执行');
199
+ log.warn('CodeX CLI invocation failed. Please run manually.');
200
200
  }
201
201
  }
202
202
  }
@@ -215,27 +215,27 @@ function checkCodexCLI() {
215
215
  }
216
216
 
217
217
  function buildParsePrompt(prdContent, copilotDir) {
218
- return `请阅读以下 PRD 文档,将其拆解为独立的开发任务。
218
+ return `Read the following PRD document and break it down into independent development tasks.
219
219
 
220
- ## 要求
221
- 1. 每个任务在一个 PR 中可以完成(粒度适中,不要太大也不要太碎)
222
- 2. 有明确的验收标准
223
- 3. 按依赖关系排序(被依赖的任务排在前面)
224
- 4. 第一个任务通常是"项目初始化 / 基础框架搭建"
220
+ ## Requirements
221
+ 1. Each task should be completable in a single PR (moderate granularity — not too large, not too small)
222
+ 2. Each task must have clear acceptance criteria
223
+ 3. Tasks should be ordered by dependency (dependent tasks first)
224
+ 4. The first task is usually "Project initialization / base framework setup"
225
225
 
226
- ## 输出格式
227
- 将结果输出到 \`.codex-copilot/tasks.json\`,格式如下:
226
+ ## Output Format
227
+ Write the result to \`.codex-copilot/tasks.json\` in the following format:
228
228
 
229
229
  \`\`\`json
230
230
  {
231
- "project": "项目名称",
231
+ "project": "Project Name",
232
232
  "total": 5,
233
233
  "tasks": [
234
234
  {
235
235
  "id": 1,
236
- "title": "任务标题(简短)",
237
- "description": "详细的任务描述,包含需要实现的具体功能和技术细节",
238
- "acceptance": ["验收条件1", "验收条件2"],
236
+ "title": "Task title (brief)",
237
+ "description": "Detailed task description with specific features and technical details",
238
+ "acceptance": ["Acceptance criteria 1", "Acceptance criteria 2"],
239
239
  "branch": "feature/001-task-slug",
240
240
  "status": "pending",
241
241
  "depends_on": []
@@ -253,7 +253,7 @@ function buildParsePrompt(prdContent, copilotDir) {
253
253
  }
254
254
  \`\`\`
255
255
 
256
- ## PRD 文档内容
256
+ ## PRD Document Content
257
257
 
258
258
  ${prdContent}
259
259
  `;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * codex-copilot reset - 重置状态
2
+ * codex-copilot reset - Reset state
3
3
  */
4
4
 
5
5
  import { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs';
@@ -12,17 +12,17 @@ export async function reset(projectDir) {
12
12
  const tasksPath = resolve(projectDir, '.codex-copilot/tasks.json');
13
13
 
14
14
  if (!existsSync(statePath)) {
15
- log.warn('项目未初始化,无需重置');
15
+ log.warn('Project not initialized, nothing to reset');
16
16
  closePrompt();
17
17
  return;
18
18
  }
19
19
 
20
- log.title('🔄 重置 Codex-Copilot 状态');
20
+ log.title('🔄 Resetting Codex-Copilot state');
21
21
  log.blank();
22
22
 
23
- const resetTasks = await confirm('是否同时重置任务状态 (所有任务标记为 pending)?', false);
23
+ const resetTasks = await confirm('Also reset all task statuses to pending?', false);
24
24
 
25
- // 重置 state
25
+ // Reset state
26
26
  const state = {
27
27
  current_task: 0,
28
28
  current_pr: null,
@@ -30,23 +30,23 @@ export async function reset(projectDir) {
30
30
  status: 'initialized',
31
31
  };
32
32
  writeFileSync(statePath, JSON.stringify(state, null, 2));
33
- log.info('执行状态已重置');
33
+ log.info('Execution state reset');
34
34
 
35
- // 重置任务状态
35
+ // Reset task statuses
36
36
  if (resetTasks && existsSync(tasksPath)) {
37
37
  const tasks = JSON.parse(readFileSync(tasksPath, 'utf-8'));
38
38
  for (const task of tasks.tasks) {
39
39
  task.status = 'pending';
40
40
  }
41
41
  writeFileSync(tasksPath, JSON.stringify(tasks, null, 2));
42
- log.info('任务状态已重置');
42
+ log.info('Task statuses reset');
43
43
  }
44
44
 
45
- // 清理临时文件
45
+ // Clean up temp files
46
46
  const promptPath = resolve(projectDir, '.codex-copilot/_current_prompt.md');
47
47
  if (existsSync(promptPath)) unlinkSync(promptPath);
48
48
 
49
49
  log.blank();
50
- log.info('✅ 重置完成,可以重新运行 codex-copilot run');
50
+ log.info('✅ Reset complete. You can now run: codex-copilot run');
51
51
  closePrompt();
52
52
  }