@jojonax/codex-copilot 1.0.2 → 1.1.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/bin/cli.js +33 -22
- package/package.json +1 -1
- package/src/commands/init.js +111 -103
- package/src/commands/reset.js +25 -17
- package/src/commands/run.js +311 -210
- package/src/commands/status.js +37 -20
- package/src/utils/automator.js +279 -0
- package/src/utils/checkpoint.js +129 -0
- package/src/utils/detect-prd.js +18 -18
- package/src/utils/git.js +22 -18
- package/src/utils/github.js +157 -21
- package/src/utils/logger.js +14 -13
- package/src/utils/prompt.js +7 -7
- package/src/utils/provider.js +332 -0
- package/src/utils/update-check.js +103 -0
package/bin/cli.js
CHANGED
|
@@ -1,31 +1,39 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* codex-copilot CLI - PRD →
|
|
4
|
+
* codex-copilot CLI - PRD → Auto Dev → PR → Review → Fix → Merge
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* codex-copilot init #
|
|
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(
|
|
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('
|
|
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('
|
|
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('
|
|
69
|
+
console.log(' Usage: codex-copilot <command>');
|
|
62
70
|
console.log('');
|
|
63
|
-
console.log('
|
|
64
|
-
console.log(' init
|
|
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 (
|
|
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(
|
|
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
package/src/commands/init.js
CHANGED
|
@@ -1,50 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* codex-copilot init -
|
|
2
|
+
* codex-copilot init - Initialize project
|
|
3
3
|
*
|
|
4
|
-
* 1.
|
|
5
|
-
* 2.
|
|
6
|
-
* 3.
|
|
7
|
-
* 4.
|
|
4
|
+
* 1. Auto-detect PRD document
|
|
5
|
+
* 2. Let user confirm/select PRD
|
|
6
|
+
* 3. Select AI provider (Codex, Claude Code, Cursor, etc.)
|
|
7
|
+
* 4. Generate task decomposition prompt
|
|
8
|
+
* 5. Create .codex-copilot/ directory structure
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'fs';
|
|
11
12
|
import { resolve } from 'path';
|
|
12
|
-
import { execSync } from 'child_process';
|
|
13
13
|
import { detectPRD, readPRD } from '../utils/detect-prd.js';
|
|
14
14
|
import { log } from '../utils/logger.js';
|
|
15
15
|
import { ask, confirm, select, closePrompt } from '../utils/prompt.js';
|
|
16
16
|
import { git } from '../utils/git.js';
|
|
17
17
|
import { github } from '../utils/github.js';
|
|
18
|
+
import { provider } from '../utils/provider.js';
|
|
18
19
|
|
|
19
20
|
export async function init(projectDir) {
|
|
20
|
-
log.title('📋
|
|
21
|
+
log.title('📋 Initializing Codex-Copilot');
|
|
21
22
|
log.blank();
|
|
22
23
|
|
|
23
|
-
// =====
|
|
24
|
-
log.step('
|
|
24
|
+
// ===== Pre-flight checks =====
|
|
25
|
+
log.step('Checking environment...');
|
|
25
26
|
|
|
26
|
-
//
|
|
27
|
+
// Check if in a git repo
|
|
27
28
|
try {
|
|
28
29
|
git.currentBranch(projectDir);
|
|
29
|
-
log.info('Git
|
|
30
|
+
log.info('Git repository ✓');
|
|
30
31
|
} catch {
|
|
31
|
-
log.error('
|
|
32
|
+
log.error('Not a Git repository. Run: git init');
|
|
32
33
|
closePrompt();
|
|
33
34
|
process.exit(1);
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
//
|
|
37
|
+
// Check gh CLI
|
|
37
38
|
if (!github.checkGhAuth()) {
|
|
38
|
-
log.error('GitHub CLI
|
|
39
|
+
log.error('GitHub CLI not authenticated. Run: gh auth login');
|
|
39
40
|
closePrompt();
|
|
40
41
|
process.exit(1);
|
|
41
42
|
}
|
|
42
43
|
log.info('GitHub CLI ✓');
|
|
43
44
|
|
|
44
|
-
//
|
|
45
|
+
// Check GitHub remote
|
|
45
46
|
try {
|
|
46
47
|
const repo = git.getRepoInfo(projectDir);
|
|
47
|
-
log.info(`GitHub
|
|
48
|
+
log.info(`GitHub repo: ${repo.owner}/${repo.repo} ✓`);
|
|
48
49
|
} catch (err) {
|
|
49
50
|
log.error(err.message);
|
|
50
51
|
closePrompt();
|
|
@@ -53,58 +54,69 @@ export async function init(projectDir) {
|
|
|
53
54
|
|
|
54
55
|
log.blank();
|
|
55
56
|
|
|
56
|
-
// =====
|
|
57
|
-
log.step('
|
|
57
|
+
// ===== Detect PRD =====
|
|
58
|
+
log.step('Scanning for PRD documents...');
|
|
58
59
|
const candidates = detectPRD(projectDir);
|
|
59
60
|
|
|
60
61
|
let prdPath;
|
|
61
62
|
|
|
62
63
|
if (candidates.length === 0) {
|
|
63
|
-
log.warn('
|
|
64
|
-
const manualPath = await ask('
|
|
64
|
+
log.warn('No PRD document detected automatically');
|
|
65
|
+
const manualPath = await ask('Enter PRD file path (relative or absolute):');
|
|
65
66
|
prdPath = resolve(projectDir, manualPath);
|
|
66
|
-
//
|
|
67
|
+
// Prevent path traversal
|
|
67
68
|
if (!prdPath.startsWith(resolve(projectDir)) && !manualPath.startsWith('/')) {
|
|
68
|
-
log.error('PRD
|
|
69
|
+
log.error('PRD path is outside the project directory');
|
|
69
70
|
closePrompt();
|
|
70
71
|
process.exit(1);
|
|
71
72
|
}
|
|
72
73
|
if (!existsSync(prdPath)) {
|
|
73
|
-
log.error(
|
|
74
|
+
log.error(`File not found: ${prdPath}`);
|
|
74
75
|
closePrompt();
|
|
75
76
|
process.exit(1);
|
|
76
77
|
}
|
|
77
78
|
} else if (candidates.length === 1) {
|
|
78
79
|
prdPath = candidates[0].path;
|
|
79
|
-
log.info(
|
|
80
|
-
const ok = await confirm('
|
|
80
|
+
log.info(`Found PRD: ${candidates[0].relativePath}`);
|
|
81
|
+
const ok = await confirm('Use this file?');
|
|
81
82
|
if (!ok) {
|
|
82
|
-
const manualPath = await ask('
|
|
83
|
+
const manualPath = await ask('Enter PRD file path:');
|
|
83
84
|
prdPath = resolve(projectDir, manualPath);
|
|
84
85
|
}
|
|
85
86
|
} else {
|
|
86
|
-
log.info(
|
|
87
|
-
const choice = await select('
|
|
88
|
-
label: `${c.relativePath} (
|
|
87
|
+
log.info(`Found ${candidates.length} candidate PRD files:`);
|
|
88
|
+
const choice = await select('Select the PRD to use:', candidates.map(c => ({
|
|
89
|
+
label: `${c.relativePath} (score: ${c.score})`,
|
|
89
90
|
value: c.path,
|
|
90
91
|
})));
|
|
91
92
|
prdPath = choice.value;
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
log.info(
|
|
95
|
+
log.info(`Using PRD: ${prdPath}`);
|
|
95
96
|
log.blank();
|
|
96
97
|
|
|
97
|
-
// =====
|
|
98
|
+
// ===== Read PRD =====
|
|
98
99
|
const prdContent = readPRD(prdPath);
|
|
99
|
-
log.info(`PRD
|
|
100
|
+
log.info(`PRD size: ${(prdContent.length / 1024).toFixed(1)} KB`);
|
|
100
101
|
|
|
101
|
-
// =====
|
|
102
|
-
log.step('
|
|
102
|
+
// ===== Select AI Provider =====
|
|
103
|
+
log.step('Select AI coding tool...');
|
|
104
|
+
log.blank();
|
|
105
|
+
const providerChoices = provider.buildProviderChoices();
|
|
106
|
+
const selectedProvider = await select('Which AI tool will you use?', providerChoices);
|
|
107
|
+
const providerId = selectedProvider.value;
|
|
108
|
+
const providerInfo = provider.getProvider(providerId);
|
|
109
|
+
log.info(`Selected: ${providerInfo.name}`);
|
|
110
|
+
log.blank();
|
|
111
|
+
|
|
112
|
+
// ===== Create .codex-copilot directory =====
|
|
113
|
+
log.step('Creating .codex-copilot/ directory...');
|
|
103
114
|
const copilotDir = resolve(projectDir, '.codex-copilot');
|
|
104
115
|
mkdirSync(copilotDir, { recursive: true });
|
|
105
116
|
|
|
106
|
-
//
|
|
117
|
+
// Write config file
|
|
107
118
|
const config = {
|
|
119
|
+
provider: providerId,
|
|
108
120
|
prd_path: prdPath,
|
|
109
121
|
base_branch: git.currentBranch(projectDir) || 'main',
|
|
110
122
|
max_review_rounds: 2,
|
|
@@ -114,37 +126,41 @@ export async function init(projectDir) {
|
|
|
114
126
|
};
|
|
115
127
|
writeFileSync(resolve(copilotDir, 'config.json'), JSON.stringify(config, null, 2));
|
|
116
128
|
|
|
117
|
-
//
|
|
129
|
+
// Write initial state (matches checkpoint.js schema)
|
|
118
130
|
const state = {
|
|
119
131
|
current_task: 0,
|
|
132
|
+
phase: null,
|
|
133
|
+
phase_step: null,
|
|
120
134
|
current_pr: null,
|
|
121
135
|
review_round: 0,
|
|
136
|
+
branch: null,
|
|
122
137
|
status: 'initialized',
|
|
138
|
+
last_updated: new Date().toISOString(),
|
|
123
139
|
};
|
|
124
140
|
writeFileSync(resolve(copilotDir, 'state.json'), JSON.stringify(state, null, 2));
|
|
125
141
|
|
|
126
|
-
//
|
|
127
|
-
const instructions = `# Codex-Copilot
|
|
142
|
+
// Write CodeX instruction template
|
|
143
|
+
const instructions = `# Codex-Copilot Development Instructions
|
|
128
144
|
|
|
129
|
-
##
|
|
130
|
-
|
|
145
|
+
## Role
|
|
146
|
+
You are an efficient automated development agent responsible for completing feature development according to task descriptions.
|
|
131
147
|
|
|
132
|
-
##
|
|
133
|
-
1.
|
|
134
|
-
2.
|
|
135
|
-
3. **Git
|
|
136
|
-
4.
|
|
137
|
-
5.
|
|
148
|
+
## Rules
|
|
149
|
+
1. **Follow the project tech stack**: Use the existing frameworks, tools, and code style
|
|
150
|
+
2. **Test first**: Ensure code compiles/runs before finishing
|
|
151
|
+
3. **Git conventions**: Commit message format \`feat(task-N): brief description\` or \`fix(task-N): brief description\`
|
|
152
|
+
4. **Don't modify unrelated files**: Only change files required by the current task
|
|
153
|
+
5. **Commit when done**: \`git add -A && git commit -m "..."\`
|
|
138
154
|
|
|
139
|
-
##
|
|
140
|
-
1.
|
|
141
|
-
2.
|
|
142
|
-
3.
|
|
143
|
-
4.
|
|
155
|
+
## Rules for fixing reviews
|
|
156
|
+
1. Read each review comment carefully
|
|
157
|
+
2. Distinguish between must-fix vs. suggestions
|
|
158
|
+
3. If you disagree with a comment, explain why in the commit message
|
|
159
|
+
4. Ensure fixes don't introduce new issues
|
|
144
160
|
`;
|
|
145
161
|
writeFileSync(resolve(copilotDir, 'codex-instructions.md'), instructions);
|
|
146
162
|
|
|
147
|
-
//
|
|
163
|
+
// Add .gitignore entries
|
|
148
164
|
const gitignorePath = resolve(projectDir, '.gitignore');
|
|
149
165
|
const gitignoreEntry = '\n# Codex-Copilot state\n.codex-copilot/state.json\n';
|
|
150
166
|
if (existsSync(gitignorePath)) {
|
|
@@ -154,88 +170,80 @@ export async function init(projectDir) {
|
|
|
154
170
|
}
|
|
155
171
|
}
|
|
156
172
|
|
|
157
|
-
log.info('.codex-copilot/
|
|
173
|
+
log.info('.codex-copilot/ directory created');
|
|
158
174
|
log.blank();
|
|
159
175
|
|
|
160
|
-
// =====
|
|
161
|
-
log.step('
|
|
176
|
+
// ===== Generate task decomposition prompt =====
|
|
177
|
+
log.step('Generating task decomposition prompt...');
|
|
162
178
|
|
|
163
179
|
const parsePrompt = buildParsePrompt(prdContent, copilotDir);
|
|
164
180
|
const promptPath = resolve(copilotDir, 'parse-prd-prompt.md');
|
|
165
181
|
writeFileSync(promptPath, parsePrompt);
|
|
166
182
|
|
|
167
|
-
log.info(
|
|
183
|
+
log.info('Task decomposition prompt saved to: .codex-copilot/parse-prd-prompt.md');
|
|
168
184
|
log.blank();
|
|
169
185
|
|
|
170
|
-
// =====
|
|
171
|
-
log.title('✅
|
|
172
|
-
log.blank();
|
|
173
|
-
log.info('接下来请执行以下步骤:');
|
|
186
|
+
// ===== Guide user to next steps =====
|
|
187
|
+
log.title('✅ Initialization complete!');
|
|
174
188
|
log.blank();
|
|
175
|
-
|
|
176
|
-
console.log(' │ 1. 打开 CodeX 桌面版 │');
|
|
177
|
-
console.log(' │ 2. 将以下文件内容粘贴给 CodeX 执行: │');
|
|
178
|
-
console.log(' │ .codex-copilot/parse-prd-prompt.md │');
|
|
179
|
-
console.log(' │ 3. CodeX 会生成 .codex-copilot/tasks.json │');
|
|
180
|
-
console.log(' │ 4. 确认任务列表后运行: │');
|
|
181
|
-
console.log(' │ codex-copilot run │');
|
|
182
|
-
console.log(' └───────────────────────────────────────────────────┘');
|
|
189
|
+
log.info(`AI Provider: ${providerInfo.name}`);
|
|
183
190
|
log.blank();
|
|
184
191
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
log.info('检测到 CodeX CLI 可用!');
|
|
189
|
-
const autoparse = await confirm('是否自动调用 CodeX 拆解 PRD?');
|
|
192
|
+
if (providerInfo.type === 'cli') {
|
|
193
|
+
// CLI provider: offer auto-decompose
|
|
194
|
+
const autoparse = await confirm(`Auto-invoke ${providerInfo.name} to decompose PRD?`);
|
|
190
195
|
if (autoparse) {
|
|
191
|
-
log.step(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
stdio: 'inherit',
|
|
196
|
-
});
|
|
197
|
-
log.info('CodeX 拆解完成!');
|
|
198
|
-
} catch {
|
|
199
|
-
log.warn('CodeX CLI 调用失败,请手动执行');
|
|
196
|
+
log.step(`Invoking ${providerInfo.name} to decompose PRD...`);
|
|
197
|
+
const ok = await provider.executePrompt(providerId, promptPath, projectDir);
|
|
198
|
+
if (ok) {
|
|
199
|
+
log.info('PRD decomposition complete!');
|
|
200
200
|
}
|
|
201
|
+
} else {
|
|
202
|
+
showManualInstructions(providerInfo);
|
|
201
203
|
}
|
|
204
|
+
} else {
|
|
205
|
+
// IDE provider: show manual instructions
|
|
206
|
+
showManualInstructions(providerInfo);
|
|
202
207
|
}
|
|
203
208
|
|
|
204
209
|
closePrompt();
|
|
205
210
|
}
|
|
206
211
|
|
|
207
|
-
function
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
212
|
+
function showManualInstructions(providerInfo) {
|
|
213
|
+
log.info('Next steps:');
|
|
214
|
+
log.blank();
|
|
215
|
+
console.log(' ┌───────────────────────────────────────────────────┐');
|
|
216
|
+
console.log(` │ 1. Open ${providerInfo.name.padEnd(40)}│`);
|
|
217
|
+
console.log(' │ 2. Paste the file content: │');
|
|
218
|
+
console.log(' │ .codex-copilot/parse-prd-prompt.md │');
|
|
219
|
+
console.log(' │ 3. AI will generate .codex-copilot/tasks.json │');
|
|
220
|
+
console.log(' │ 4. Then run: codex-copilot run │');
|
|
221
|
+
console.log(' └───────────────────────────────────────────────────┘');
|
|
222
|
+
log.blank();
|
|
215
223
|
}
|
|
216
224
|
|
|
217
225
|
function buildParsePrompt(prdContent, copilotDir) {
|
|
218
|
-
return
|
|
226
|
+
return `Read the following PRD document and break it down into independent development tasks.
|
|
219
227
|
|
|
220
|
-
##
|
|
221
|
-
1.
|
|
222
|
-
2.
|
|
223
|
-
3.
|
|
224
|
-
4.
|
|
228
|
+
## Requirements
|
|
229
|
+
1. Each task should be completable in a single PR (moderate granularity — not too large, not too small)
|
|
230
|
+
2. Each task must have clear acceptance criteria
|
|
231
|
+
3. Tasks should be ordered by dependency (dependent tasks first)
|
|
232
|
+
4. The first task is usually "Project initialization / base framework setup"
|
|
225
233
|
|
|
226
|
-
##
|
|
227
|
-
|
|
234
|
+
## Output Format
|
|
235
|
+
Write the result to \`.codex-copilot/tasks.json\` in the following format:
|
|
228
236
|
|
|
229
237
|
\`\`\`json
|
|
230
238
|
{
|
|
231
|
-
"project": "
|
|
239
|
+
"project": "Project Name",
|
|
232
240
|
"total": 5,
|
|
233
241
|
"tasks": [
|
|
234
242
|
{
|
|
235
243
|
"id": 1,
|
|
236
|
-
"title": "
|
|
237
|
-
"description": "
|
|
238
|
-
"acceptance": ["
|
|
244
|
+
"title": "Task title (brief)",
|
|
245
|
+
"description": "Detailed task description with specific features and technical details",
|
|
246
|
+
"acceptance": ["Acceptance criteria 1", "Acceptance criteria 2"],
|
|
239
247
|
"branch": "feature/001-task-slug",
|
|
240
248
|
"status": "pending",
|
|
241
249
|
"depends_on": []
|
|
@@ -253,7 +261,7 @@ function buildParsePrompt(prdContent, copilotDir) {
|
|
|
253
261
|
}
|
|
254
262
|
\`\`\`
|
|
255
263
|
|
|
256
|
-
## PRD
|
|
264
|
+
## PRD Document Content
|
|
257
265
|
|
|
258
266
|
${prdContent}
|
|
259
267
|
`;
|
package/src/commands/reset.js
CHANGED
|
@@ -1,52 +1,60 @@
|
|
|
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';
|
|
6
6
|
import { resolve } from 'path';
|
|
7
7
|
import { log } from '../utils/logger.js';
|
|
8
8
|
import { confirm, closePrompt } from '../utils/prompt.js';
|
|
9
|
+
import { createCheckpoint } from '../utils/checkpoint.js';
|
|
9
10
|
|
|
10
11
|
export async function reset(projectDir) {
|
|
11
12
|
const statePath = resolve(projectDir, '.codex-copilot/state.json');
|
|
12
13
|
const tasksPath = resolve(projectDir, '.codex-copilot/tasks.json');
|
|
13
14
|
|
|
14
15
|
if (!existsSync(statePath)) {
|
|
15
|
-
log.warn('
|
|
16
|
+
log.warn('Project not initialized, nothing to reset');
|
|
16
17
|
closePrompt();
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
log.title('🔄
|
|
21
|
+
log.title('🔄 Resetting Codex-Copilot state');
|
|
21
22
|
log.blank();
|
|
22
23
|
|
|
23
|
-
const
|
|
24
|
+
const checkpoint = createCheckpoint(projectDir);
|
|
25
|
+
const state = checkpoint.load();
|
|
24
26
|
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
33
|
-
log.info('执行状态已重置');
|
|
27
|
+
// Show current checkpoint before reset
|
|
28
|
+
if (state.phase) {
|
|
29
|
+
log.info(`Current checkpoint: Task #${state.current_task} — ${state.phase} → ${state.phase_step}`);
|
|
30
|
+
log.blank();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const resetTasks = await confirm('Also reset all task statuses to pending?', false);
|
|
34
34
|
|
|
35
|
-
//
|
|
35
|
+
// Reset state using checkpoint manager
|
|
36
|
+
checkpoint.reset();
|
|
37
|
+
log.info('Execution state reset');
|
|
38
|
+
|
|
39
|
+
// Reset task statuses
|
|
36
40
|
if (resetTasks && existsSync(tasksPath)) {
|
|
37
41
|
const tasks = JSON.parse(readFileSync(tasksPath, 'utf-8'));
|
|
38
42
|
for (const task of tasks.tasks) {
|
|
39
43
|
task.status = 'pending';
|
|
40
44
|
}
|
|
41
45
|
writeFileSync(tasksPath, JSON.stringify(tasks, null, 2));
|
|
42
|
-
log.info('
|
|
46
|
+
log.info('Task statuses reset');
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
//
|
|
49
|
+
// Clean up temp files
|
|
46
50
|
const promptPath = resolve(projectDir, '.codex-copilot/_current_prompt.md');
|
|
47
51
|
if (existsSync(promptPath)) unlinkSync(promptPath);
|
|
48
52
|
|
|
53
|
+
// Clean up temp state file if exists
|
|
54
|
+
const tempPath = resolve(projectDir, '.codex-copilot/state.json.tmp');
|
|
55
|
+
if (existsSync(tempPath)) unlinkSync(tempPath);
|
|
56
|
+
|
|
49
57
|
log.blank();
|
|
50
|
-
log.info('✅
|
|
58
|
+
log.info('✅ Reset complete. You can now run: codex-copilot run');
|
|
51
59
|
closePrompt();
|
|
52
60
|
}
|