@jojonax/codex-copilot 1.0.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/LICENSE +21 -0
- package/README.md +127 -0
- package/bin/cli.js +84 -0
- package/package.json +39 -0
- package/src/commands/init.js +257 -0
- package/src/commands/reset.js +52 -0
- package/src/commands/run.js +413 -0
- package/src/commands/status.js +52 -0
- package/src/utils/detect-prd.js +137 -0
- package/src/utils/git.js +95 -0
- package/src/utils/github.js +140 -0
- package/src/utils/logger.js +35 -0
- package/src/utils/prompt.js +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jonas Qin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Codex-Copilot 🤖
|
|
2
|
+
|
|
3
|
+
**PRD-driven automated development orchestrator for CodeX / Cursor**
|
|
4
|
+
|
|
5
|
+
Turn your PRD into working code — automatically. Codex-Copilot reads your product requirement docs, breaks them into tasks, drives CodeX/Cursor to develop each feature, submits PRs, waits for AI code review, fixes issues, and merges — all in a loop.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
PRD → Tasks → CodeX Dev → PR → AI Review → Fix → Merge → Next Task
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Install globally
|
|
15
|
+
npm install -g codex-copilot
|
|
16
|
+
|
|
17
|
+
# Or run directly without installing
|
|
18
|
+
npx codex-copilot
|
|
19
|
+
|
|
20
|
+
# In your project directory:
|
|
21
|
+
codex-copilot init # Detect PRD, generate task queue
|
|
22
|
+
codex-copilot run # Start the automated dev loop
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## How It Works
|
|
26
|
+
|
|
27
|
+
### 1. `codex-copilot init`
|
|
28
|
+
|
|
29
|
+
- 🔍 **Auto-detects PRD** files in your project (by filename, size, content keywords)
|
|
30
|
+
- 📋 Generates a task decomposition prompt for CodeX
|
|
31
|
+
- 🗂️ Creates `.codex-copilot/` with config, state, and instructions
|
|
32
|
+
|
|
33
|
+
### 2. Execute the PRD prompt in CodeX
|
|
34
|
+
|
|
35
|
+
- Paste the generated prompt into CodeX desktop (or use CodeX CLI if available)
|
|
36
|
+
- CodeX breaks down your PRD into ordered, independent tasks → `tasks.json`
|
|
37
|
+
|
|
38
|
+
### 3. `codex-copilot run`
|
|
39
|
+
|
|
40
|
+
Loops through each task in 4 phases:
|
|
41
|
+
|
|
42
|
+
| Phase | What Happens |
|
|
43
|
+
|-------|-------------|
|
|
44
|
+
| **1. Develop** | Creates feature branch, generates dev prompt, copies to clipboard |
|
|
45
|
+
| **2. PR** | Auto commits, pushes, creates GitHub PR via `gh` CLI |
|
|
46
|
+
| **3. Review** | Polls for AI review (Gemini Code Assist), collects feedback |
|
|
47
|
+
| **4. Merge** | Squash merges after approval, moves to next task |
|
|
48
|
+
|
|
49
|
+
### Other Commands
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
codex-copilot status # Progress bar + task list
|
|
53
|
+
codex-copilot reset # Reset and start over
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Prerequisites
|
|
57
|
+
|
|
58
|
+
| Tool | Install |
|
|
59
|
+
|------|---------|
|
|
60
|
+
| Node.js ≥ 18 | `brew install node` |
|
|
61
|
+
| GitHub CLI | `brew install gh && gh auth login` |
|
|
62
|
+
| [Gemini Code Assist](https://github.com/marketplace/gemini-code-assist) | Install on your GitHub repo |
|
|
63
|
+
| CodeX Desktop / Cursor | Official installer |
|
|
64
|
+
|
|
65
|
+
## Features
|
|
66
|
+
|
|
67
|
+
- **🔍 Smart PRD Detection** — scans project dirs, scores candidates by filename pattern + content analysis
|
|
68
|
+
- **🔄 Breakpoint Resume** — `state.json` persists progress; interrupted runs continue from last task
|
|
69
|
+
- **📋 Clipboard Integration** — auto-copies prompts to clipboard (macOS `pbcopy`)
|
|
70
|
+
- **🤖 Dual Mode** — full-auto with CodeX CLI, or manual clipboard mode for desktop app
|
|
71
|
+
- **🔁 Review Loop** — max 2 rounds of AI review + fix, with human override options
|
|
72
|
+
- **⚙️ Configurable** — edit `.codex-copilot/config.json` for timeouts, branch names, review rounds
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
After `init`, edit `.codex-copilot/config.json`:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"base_branch": "main",
|
|
81
|
+
"max_review_rounds": 2,
|
|
82
|
+
"review_poll_interval": 60,
|
|
83
|
+
"review_wait_timeout": 600
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Project Structure
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
.codex-copilot/ # Created in your project
|
|
91
|
+
├── config.json # Settings
|
|
92
|
+
├── state.json # Run state (auto-managed)
|
|
93
|
+
├── tasks.json # Task queue (CodeX-generated)
|
|
94
|
+
├── codex-instructions.md # CodeX system prompt
|
|
95
|
+
└── _current_prompt.md # Current prompt (auto-copied to clipboard)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## How the Review Loop Works
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
CodeX develops feature
|
|
102
|
+
↓
|
|
103
|
+
Push + Create PR
|
|
104
|
+
↓
|
|
105
|
+
Wait for AI Review (Gemini Code Assist)
|
|
106
|
+
↓
|
|
107
|
+
┌─ APPROVED → Merge → Next Task
|
|
108
|
+
└─ CHANGES_REQUESTED → Collect feedback
|
|
109
|
+
↓
|
|
110
|
+
Generate fix prompt → CodeX fixes
|
|
111
|
+
↓
|
|
112
|
+
Push → Wait for re-review
|
|
113
|
+
↓
|
|
114
|
+
(max 2 rounds, then human decides)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Roadmap
|
|
118
|
+
|
|
119
|
+
- [ ] Support for more AI review tools (CodeRabbit, GitHub Copilot Review)
|
|
120
|
+
- [ ] Built-in task decomposition (no manual CodeX step)
|
|
121
|
+
- [ ] Web dashboard for monitoring multiple projects
|
|
122
|
+
- [ ] GitHub Action for fully server-side automation
|
|
123
|
+
- [ ] Support for monorepo / multi-package projects
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT © Jonas Qin
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* codex-copilot CLI - PRD → 自动开发 → PR → Review → 修复 → 合并
|
|
5
|
+
*
|
|
6
|
+
* 用法:
|
|
7
|
+
* codex-copilot init # 初始化项目(自动检测 PRD,生成任务)
|
|
8
|
+
* codex-copilot run # 启动自动化开发循环
|
|
9
|
+
* codex-copilot status # 查看当前进度
|
|
10
|
+
* codex-copilot reset # 重置状态(重新开始)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { fileURLToPath } from 'url';
|
|
14
|
+
import { dirname, resolve } from 'path';
|
|
15
|
+
import { existsSync } from 'fs';
|
|
16
|
+
|
|
17
|
+
import { init } from '../src/commands/init.js';
|
|
18
|
+
import { run } from '../src/commands/run.js';
|
|
19
|
+
import { status } from '../src/commands/status.js';
|
|
20
|
+
import { reset } from '../src/commands/reset.js';
|
|
21
|
+
import { log } from '../src/utils/logger.js';
|
|
22
|
+
|
|
23
|
+
const command = process.argv[2];
|
|
24
|
+
const projectDir = process.cwd();
|
|
25
|
+
|
|
26
|
+
// Banner
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log(' ╔══════════════════════════════════════════╗');
|
|
29
|
+
console.log(' ║ 🤖 Codex-Copilot v1.0 ║');
|
|
30
|
+
console.log(' ║ PRD-Driven Auto Development ║');
|
|
31
|
+
console.log(' ╚══════════════════════════════════════════╝');
|
|
32
|
+
console.log('');
|
|
33
|
+
|
|
34
|
+
async function main() {
|
|
35
|
+
try {
|
|
36
|
+
switch (command) {
|
|
37
|
+
case 'init':
|
|
38
|
+
await init(projectDir);
|
|
39
|
+
break;
|
|
40
|
+
|
|
41
|
+
case 'run':
|
|
42
|
+
if (!existsSync(resolve(projectDir, '.codex-copilot/tasks.json'))) {
|
|
43
|
+
log.error('尚未初始化,请先运行: codex-copilot init');
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
await run(projectDir);
|
|
47
|
+
break;
|
|
48
|
+
|
|
49
|
+
case 'status':
|
|
50
|
+
if (!existsSync(resolve(projectDir, '.codex-copilot/tasks.json'))) {
|
|
51
|
+
log.error('尚未初始化,请先运行: codex-copilot init');
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
await status(projectDir);
|
|
55
|
+
break;
|
|
56
|
+
|
|
57
|
+
case 'reset':
|
|
58
|
+
await reset(projectDir);
|
|
59
|
+
break;
|
|
60
|
+
|
|
61
|
+
default:
|
|
62
|
+
console.log(' 用法: codex-copilot <command>');
|
|
63
|
+
console.log('');
|
|
64
|
+
console.log(' 命令:');
|
|
65
|
+
console.log(' init 初始化项目(自动检测 PRD,生成任务队列)');
|
|
66
|
+
console.log(' run 启动自动化开发循环');
|
|
67
|
+
console.log(' status 查看当前任务进度');
|
|
68
|
+
console.log(' reset 重置状态,重新开始');
|
|
69
|
+
console.log('');
|
|
70
|
+
console.log(' 工作流程:');
|
|
71
|
+
console.log(' 1. cd 到你的项目目录');
|
|
72
|
+
console.log(' 2. codex-copilot init (自动检测 PRD 并拆解任务)');
|
|
73
|
+
console.log(' 3. codex-copilot run (开始自动开发循环)');
|
|
74
|
+
console.log('');
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
} catch (err) {
|
|
78
|
+
log.error(`执行失败: ${err.message}`);
|
|
79
|
+
if (process.env.DEBUG) console.error(err);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jojonax/codex-copilot",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "PRD-driven automated development orchestrator for CodeX / Cursor",
|
|
5
|
+
"bin": {
|
|
6
|
+
"codex-copilot": "./bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"keywords": [
|
|
16
|
+
"codex",
|
|
17
|
+
"cursor",
|
|
18
|
+
"ai",
|
|
19
|
+
"automation",
|
|
20
|
+
"prd",
|
|
21
|
+
"code-review",
|
|
22
|
+
"github",
|
|
23
|
+
"developer-tools",
|
|
24
|
+
"cli"
|
|
25
|
+
],
|
|
26
|
+
"author": "Jonas Qin",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/jonasqin/codex-copilot.git"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/jonasqin/codex-copilot#readme",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/jonasqin/codex-copilot/issues"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* codex-copilot init - 初始化项目
|
|
3
|
+
*
|
|
4
|
+
* 1. 自动检测 PRD 文档
|
|
5
|
+
* 2. 让用户确认/选择 PRD
|
|
6
|
+
* 3. 生成 CodeX 可执行的任务拆解 Prompt
|
|
7
|
+
* 4. 创建 .codex-copilot/ 目录结构
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { mkdirSync, writeFileSync, readFileSync, existsSync, copyFileSync } from 'fs';
|
|
11
|
+
import { resolve, dirname } from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { execSync } from 'child_process';
|
|
14
|
+
import { detectPRD, readPRD } from '../utils/detect-prd.js';
|
|
15
|
+
import { log } from '../utils/logger.js';
|
|
16
|
+
import { ask, confirm, select, closePrompt } from '../utils/prompt.js';
|
|
17
|
+
import { git } from '../utils/git.js';
|
|
18
|
+
import { github } from '../utils/github.js';
|
|
19
|
+
|
|
20
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
|
|
22
|
+
export async function init(projectDir) {
|
|
23
|
+
log.title('📋 初始化 Codex-Copilot');
|
|
24
|
+
log.blank();
|
|
25
|
+
|
|
26
|
+
// ===== 前置检查 =====
|
|
27
|
+
log.step('检查环境...');
|
|
28
|
+
|
|
29
|
+
// 检查是否在 git 仓库中
|
|
30
|
+
try {
|
|
31
|
+
git.currentBranch(projectDir);
|
|
32
|
+
log.info('Git 仓库 ✓');
|
|
33
|
+
} catch {
|
|
34
|
+
log.error('当前目录不是 Git 仓库,请先 git init');
|
|
35
|
+
closePrompt();
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 检查 gh CLI
|
|
40
|
+
if (!github.checkGhAuth()) {
|
|
41
|
+
log.error('GitHub CLI 未登录,请先运行: gh auth login');
|
|
42
|
+
closePrompt();
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
log.info('GitHub CLI ✓');
|
|
46
|
+
|
|
47
|
+
// 检查 GitHub remote
|
|
48
|
+
try {
|
|
49
|
+
const repo = git.getRepoInfo(projectDir);
|
|
50
|
+
log.info(`GitHub 仓库: ${repo.owner}/${repo.repo} ✓`);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
log.error(err.message);
|
|
53
|
+
closePrompt();
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
log.blank();
|
|
58
|
+
|
|
59
|
+
// ===== 检测 PRD =====
|
|
60
|
+
log.step('扫描 PRD 文档...');
|
|
61
|
+
const candidates = detectPRD(projectDir);
|
|
62
|
+
|
|
63
|
+
let prdPath;
|
|
64
|
+
|
|
65
|
+
if (candidates.length === 0) {
|
|
66
|
+
log.warn('未自动检测到 PRD 文档');
|
|
67
|
+
const manualPath = await ask('请输入 PRD 文件路径(相对或绝对路径):');
|
|
68
|
+
prdPath = resolve(projectDir, manualPath);
|
|
69
|
+
if (!existsSync(prdPath)) {
|
|
70
|
+
log.error(`文件不存在: ${prdPath}`);
|
|
71
|
+
closePrompt();
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
} else if (candidates.length === 1) {
|
|
75
|
+
prdPath = candidates[0].path;
|
|
76
|
+
log.info(`找到 PRD: ${candidates[0].relativePath}`);
|
|
77
|
+
const ok = await confirm('使用该文件?');
|
|
78
|
+
if (!ok) {
|
|
79
|
+
const manualPath = await ask('请输入 PRD 文件路径:');
|
|
80
|
+
prdPath = resolve(projectDir, manualPath);
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
log.info(`找到 ${candidates.length} 个候选 PRD 文件:`);
|
|
84
|
+
const choice = await select('请选择要使用的 PRD:', candidates.map(c => ({
|
|
85
|
+
label: `${c.relativePath} (匹配度: ${c.score})`,
|
|
86
|
+
value: c.path,
|
|
87
|
+
})));
|
|
88
|
+
prdPath = choice.value;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
log.info(`使用 PRD: ${prdPath}`);
|
|
92
|
+
log.blank();
|
|
93
|
+
|
|
94
|
+
// ===== 读取 PRD =====
|
|
95
|
+
const prdContent = readPRD(prdPath);
|
|
96
|
+
log.info(`PRD 大小: ${(prdContent.length / 1024).toFixed(1)} KB`);
|
|
97
|
+
|
|
98
|
+
// ===== 创建 .codex-copilot 目录 =====
|
|
99
|
+
log.step('创建 .codex-copilot/ 目录...');
|
|
100
|
+
const copilotDir = resolve(projectDir, '.codex-copilot');
|
|
101
|
+
mkdirSync(copilotDir, { recursive: true });
|
|
102
|
+
|
|
103
|
+
// 写入配置文件
|
|
104
|
+
const config = {
|
|
105
|
+
prd_path: prdPath,
|
|
106
|
+
base_branch: git.currentBranch(projectDir) || 'main',
|
|
107
|
+
max_review_rounds: 2,
|
|
108
|
+
review_poll_interval: 60,
|
|
109
|
+
review_wait_timeout: 600,
|
|
110
|
+
created_at: new Date().toISOString(),
|
|
111
|
+
};
|
|
112
|
+
writeFileSync(resolve(copilotDir, 'config.json'), JSON.stringify(config, null, 2));
|
|
113
|
+
|
|
114
|
+
// 写入初始状态
|
|
115
|
+
const state = {
|
|
116
|
+
current_task: 0,
|
|
117
|
+
current_pr: null,
|
|
118
|
+
review_round: 0,
|
|
119
|
+
status: 'initialized',
|
|
120
|
+
};
|
|
121
|
+
writeFileSync(resolve(copilotDir, 'state.json'), JSON.stringify(state, null, 2));
|
|
122
|
+
|
|
123
|
+
// 写入 CodeX 指令模板
|
|
124
|
+
const instructions = `# Codex-Copilot 开发指令
|
|
125
|
+
|
|
126
|
+
## 角色
|
|
127
|
+
你是一个高效的自动开发 Agent,负责按照任务描述完成功能开发。
|
|
128
|
+
|
|
129
|
+
## 规则
|
|
130
|
+
1. **严格遵循项目技术栈**:使用项目已有的框架、工具和代码风格
|
|
131
|
+
2. **自测优先**:开发完成前确保代码可以编译/运行
|
|
132
|
+
3. **Git 规范**:提交信息格式 \`feat(task-N): 简要描述\` 或 \`fix(task-N): 简要描述\`
|
|
133
|
+
4. **不要修改无关文件**:只修改当前任务需要的文件
|
|
134
|
+
5. **完成后执行 git commit**:\`git add -A && git commit -m "..."\`
|
|
135
|
+
|
|
136
|
+
## 修复 Review 时的规则
|
|
137
|
+
1. 逐条阅读 Review 意见
|
|
138
|
+
2. 区分必须修复 vs 建议性意见
|
|
139
|
+
3. 对于不认同的意见,在 commit message 中说明原因
|
|
140
|
+
4. 修复后确保不引入新问题
|
|
141
|
+
`;
|
|
142
|
+
writeFileSync(resolve(copilotDir, 'codex-instructions.md'), instructions);
|
|
143
|
+
|
|
144
|
+
// 添加 .gitignore 项
|
|
145
|
+
const gitignorePath = resolve(projectDir, '.gitignore');
|
|
146
|
+
const gitignoreEntry = '\n# Codex-Copilot state\n.codex-copilot/state.json\n';
|
|
147
|
+
if (existsSync(gitignorePath)) {
|
|
148
|
+
const content = readFileSync(gitignorePath, 'utf-8');
|
|
149
|
+
if (!content.includes('.codex-copilot/state.json')) {
|
|
150
|
+
writeFileSync(gitignorePath, content + gitignoreEntry);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
log.info('.codex-copilot/ 目录已创建');
|
|
155
|
+
log.blank();
|
|
156
|
+
|
|
157
|
+
// ===== 生成任务拆解 Prompt =====
|
|
158
|
+
log.step('生成任务拆解 Prompt...');
|
|
159
|
+
|
|
160
|
+
const parsePrompt = buildParsePrompt(prdContent, copilotDir);
|
|
161
|
+
const promptPath = resolve(copilotDir, 'parse-prd-prompt.md');
|
|
162
|
+
writeFileSync(promptPath, parsePrompt);
|
|
163
|
+
|
|
164
|
+
log.info(`任务拆解 Prompt 已保存到: .codex-copilot/parse-prd-prompt.md`);
|
|
165
|
+
log.blank();
|
|
166
|
+
|
|
167
|
+
// ===== 提示用户下一步 =====
|
|
168
|
+
log.title('✅ 初始化完成!');
|
|
169
|
+
log.blank();
|
|
170
|
+
log.info('接下来请执行以下步骤:');
|
|
171
|
+
log.blank();
|
|
172
|
+
console.log(' ┌───────────────────────────────────────────────────┐');
|
|
173
|
+
console.log(' │ 1. 打开 CodeX 桌面版 │');
|
|
174
|
+
console.log(' │ 2. 将以下文件内容粘贴给 CodeX 执行: │');
|
|
175
|
+
console.log(' │ .codex-copilot/parse-prd-prompt.md │');
|
|
176
|
+
console.log(' │ 3. CodeX 会生成 .codex-copilot/tasks.json │');
|
|
177
|
+
console.log(' │ 4. 确认任务列表后运行: │');
|
|
178
|
+
console.log(' │ codex-copilot run │');
|
|
179
|
+
console.log(' └───────────────────────────────────────────────────┘');
|
|
180
|
+
log.blank();
|
|
181
|
+
|
|
182
|
+
// 询问是否尝试自动拆解(如果 codex CLI 可用)
|
|
183
|
+
const hasCodexCLI = checkCodexCLI();
|
|
184
|
+
if (hasCodexCLI) {
|
|
185
|
+
log.info('检测到 CodeX CLI 可用!');
|
|
186
|
+
const autoparse = await confirm('是否自动调用 CodeX 拆解 PRD?');
|
|
187
|
+
if (autoparse) {
|
|
188
|
+
log.step('调用 CodeX CLI 拆解 PRD...');
|
|
189
|
+
try {
|
|
190
|
+
const { execSync } = await import('child_process');
|
|
191
|
+
execSync(`codex -q "${parsePrompt.slice(0, 2000)}"`, {
|
|
192
|
+
cwd: projectDir,
|
|
193
|
+
stdio: 'inherit',
|
|
194
|
+
});
|
|
195
|
+
log.info('CodeX 拆解完成!');
|
|
196
|
+
} catch {
|
|
197
|
+
log.warn('CodeX CLI 调用失败,请手动执行');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
closePrompt();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function checkCodexCLI() {
|
|
206
|
+
try {
|
|
207
|
+
execSync('which codex', { stdio: 'pipe' });
|
|
208
|
+
return true;
|
|
209
|
+
} catch {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function buildParsePrompt(prdContent, copilotDir) {
|
|
215
|
+
return `请阅读以下 PRD 文档,将其拆解为独立的开发任务。
|
|
216
|
+
|
|
217
|
+
## 要求
|
|
218
|
+
1. 每个任务在一个 PR 中可以完成(粒度适中,不要太大也不要太碎)
|
|
219
|
+
2. 有明确的验收标准
|
|
220
|
+
3. 按依赖关系排序(被依赖的任务排在前面)
|
|
221
|
+
4. 第一个任务通常是"项目初始化 / 基础框架搭建"
|
|
222
|
+
|
|
223
|
+
## 输出格式
|
|
224
|
+
将结果输出到 \`.codex-copilot/tasks.json\`,格式如下:
|
|
225
|
+
|
|
226
|
+
\`\`\`json
|
|
227
|
+
{
|
|
228
|
+
"project": "项目名称",
|
|
229
|
+
"total": 5,
|
|
230
|
+
"tasks": [
|
|
231
|
+
{
|
|
232
|
+
"id": 1,
|
|
233
|
+
"title": "任务标题(简短)",
|
|
234
|
+
"description": "详细的任务描述,包含需要实现的具体功能和技术细节",
|
|
235
|
+
"acceptance": ["验收条件1", "验收条件2"],
|
|
236
|
+
"branch": "feature/001-task-slug",
|
|
237
|
+
"status": "pending",
|
|
238
|
+
"depends_on": []
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"id": 2,
|
|
242
|
+
"title": "...",
|
|
243
|
+
"description": "...",
|
|
244
|
+
"acceptance": ["..."],
|
|
245
|
+
"branch": "feature/002-task-slug",
|
|
246
|
+
"status": "pending",
|
|
247
|
+
"depends_on": [1]
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
\`\`\`
|
|
252
|
+
|
|
253
|
+
## PRD 文档内容
|
|
254
|
+
|
|
255
|
+
${prdContent}
|
|
256
|
+
`;
|
|
257
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* codex-copilot reset - 重置状态
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs';
|
|
6
|
+
import { resolve } from 'path';
|
|
7
|
+
import { log } from '../utils/logger.js';
|
|
8
|
+
import { confirm, closePrompt } from '../utils/prompt.js';
|
|
9
|
+
|
|
10
|
+
export async function reset(projectDir) {
|
|
11
|
+
const statePath = resolve(projectDir, '.codex-copilot/state.json');
|
|
12
|
+
const tasksPath = resolve(projectDir, '.codex-copilot/tasks.json');
|
|
13
|
+
|
|
14
|
+
if (!existsSync(statePath)) {
|
|
15
|
+
log.warn('项目未初始化,无需重置');
|
|
16
|
+
closePrompt();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
log.title('🔄 重置 Codex-Copilot 状态');
|
|
21
|
+
log.blank();
|
|
22
|
+
|
|
23
|
+
const resetTasks = await confirm('是否同时重置任务状态 (所有任务标记为 pending)?', false);
|
|
24
|
+
|
|
25
|
+
// 重置 state
|
|
26
|
+
const state = {
|
|
27
|
+
current_task: 0,
|
|
28
|
+
current_pr: null,
|
|
29
|
+
review_round: 0,
|
|
30
|
+
status: 'initialized',
|
|
31
|
+
};
|
|
32
|
+
writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
33
|
+
log.info('执行状态已重置');
|
|
34
|
+
|
|
35
|
+
// 重置任务状态
|
|
36
|
+
if (resetTasks && existsSync(tasksPath)) {
|
|
37
|
+
const tasks = JSON.parse(readFileSync(tasksPath, 'utf-8'));
|
|
38
|
+
for (const task of tasks.tasks) {
|
|
39
|
+
task.status = 'pending';
|
|
40
|
+
}
|
|
41
|
+
writeFileSync(tasksPath, JSON.stringify(tasks, null, 2));
|
|
42
|
+
log.info('任务状态已重置');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 清理临时文件
|
|
46
|
+
const promptPath = resolve(projectDir, '.codex-copilot/_current_prompt.md');
|
|
47
|
+
if (existsSync(promptPath)) unlinkSync(promptPath);
|
|
48
|
+
|
|
49
|
+
log.blank();
|
|
50
|
+
log.info('✅ 重置完成,可以重新运行 codex-copilot run');
|
|
51
|
+
closePrompt();
|
|
52
|
+
}
|