openplanr 0.8.0 → 0.9.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/README.md +11 -5
- package/dist/ai/prompts/prompt-builder.d.ts.map +1 -1
- package/dist/ai/prompts/prompt-builder.js +8 -1
- package/dist/ai/prompts/prompt-builder.js.map +1 -1
- package/dist/ai/prompts/system-prompts.d.ts +1 -1
- package/dist/ai/prompts/system-prompts.d.ts.map +1 -1
- package/dist/ai/prompts/system-prompts.js +2 -1
- package/dist/ai/prompts/system-prompts.js.map +1 -1
- package/dist/ai/types.d.ts +1 -1
- package/dist/ai/types.js +1 -1
- package/dist/cli/commands/epic.d.ts.map +1 -1
- package/dist/cli/commands/epic.js +16 -3
- package/dist/cli/commands/epic.js.map +1 -1
- package/dist/cli/commands/export.d.ts +8 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +280 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/github.d.ts +8 -0
- package/dist/cli/commands/github.d.ts.map +1 -0
- package/dist/cli/commands/github.js +412 -0
- package/dist/cli/commands/github.js.map +1 -0
- package/dist/cli/commands/plan.d.ts.map +1 -1
- package/dist/cli/commands/plan.js +89 -20
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/services/github-service.d.ts +83 -0
- package/dist/services/github-service.d.ts.map +1 -0
- package/dist/services/github-service.js +435 -0
- package/dist/services/github-service.js.map +1 -0
- package/dist/services/template-service.d.ts.map +1 -1
- package/dist/services/template-service.js +1 -0
- package/dist/services/template-service.js.map +1 -1
- package/dist/templates/export/planning-report.html.hbs +230 -0
- package/dist/templates/export/planning-report.md.hbs +136 -0
- package/package.json +1 -1
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr github` command.
|
|
3
|
+
*
|
|
4
|
+
* Push planning artifacts to GitHub Issues and sync status bi-directionally.
|
|
5
|
+
*/
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { findArtifactTypeById, listArtifacts, readArtifact, readArtifactRaw, updateArtifact, } from '../../services/artifact-service.js';
|
|
8
|
+
import { loadConfig } from '../../services/config-service.js';
|
|
9
|
+
import { buildIssueBody, cleanTitle, createIssue, ensureLabel, ensureMilestone, getIssue, getLabelForType, issueStateToStatus, statusToIssueState, updateIssue, verifyGitHubRepo, } from '../../services/github-service.js';
|
|
10
|
+
import { promptSelect } from '../../services/prompt-service.js';
|
|
11
|
+
import { logger } from '../../utils/logger.js';
|
|
12
|
+
import { parseMarkdown, toMarkdownWithFrontmatter } from '../../utils/markdown.js';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Helpers
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/** Inject or update a `githubIssue` field in raw artifact frontmatter. */
|
|
17
|
+
function setFrontmatterField(raw, field, value) {
|
|
18
|
+
const escaped = field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
19
|
+
const fieldRegex = new RegExp(`^${escaped}:.*\\n`, 'm');
|
|
20
|
+
if (fieldRegex.test(raw)) {
|
|
21
|
+
return raw.replace(fieldRegex, `${field}: ${value}\n`);
|
|
22
|
+
}
|
|
23
|
+
// Insert before closing ---
|
|
24
|
+
const closingIdx = raw.indexOf('\n---', raw.indexOf('---') + 3);
|
|
25
|
+
if (closingIdx !== -1) {
|
|
26
|
+
return `${raw.slice(0, closingIdx)}\n${field}: ${value}${raw.slice(closingIdx)}`;
|
|
27
|
+
}
|
|
28
|
+
return raw;
|
|
29
|
+
}
|
|
30
|
+
/** Push a single artifact to GitHub as an issue. */
|
|
31
|
+
async function pushSingleArtifact(projectDir, config, artifactId, opts) {
|
|
32
|
+
const type = findArtifactTypeById(artifactId);
|
|
33
|
+
if (!type) {
|
|
34
|
+
logger.error(`Cannot determine artifact type from ID: ${artifactId}`);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const artifact = await readArtifact(projectDir, config, type, artifactId);
|
|
38
|
+
if (!artifact) {
|
|
39
|
+
logger.error(`Artifact not found: ${artifactId}`);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const raw = await readArtifactRaw(projectDir, config, type, artifactId);
|
|
43
|
+
if (!raw)
|
|
44
|
+
return null;
|
|
45
|
+
const title = cleanTitle(artifactId, artifact.data.title);
|
|
46
|
+
const body = buildIssueBody(raw, artifactId, type, artifact.data);
|
|
47
|
+
// Ensure label exists
|
|
48
|
+
const label = getLabelForType(type);
|
|
49
|
+
if (label)
|
|
50
|
+
await ensureLabel(label);
|
|
51
|
+
const labels = label ? [label] : [];
|
|
52
|
+
const existingIssueNumber = artifact.data.githubIssue;
|
|
53
|
+
let issueNumber;
|
|
54
|
+
let issueUrl;
|
|
55
|
+
let action;
|
|
56
|
+
if (existingIssueNumber) {
|
|
57
|
+
// Try to update existing issue — fall back to create if deleted on GitHub
|
|
58
|
+
try {
|
|
59
|
+
const currentIssue = await getIssue(existingIssueNumber);
|
|
60
|
+
await updateIssue(existingIssueNumber, { title, body });
|
|
61
|
+
const status = artifact.data.status || 'pending';
|
|
62
|
+
const targetState = statusToIssueState(status);
|
|
63
|
+
if (currentIssue.state !== targetState) {
|
|
64
|
+
await updateIssue(existingIssueNumber, { state: targetState });
|
|
65
|
+
}
|
|
66
|
+
issueNumber = existingIssueNumber;
|
|
67
|
+
issueUrl = currentIssue.url;
|
|
68
|
+
action = 'updated';
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Issue was deleted on GitHub — create a fresh one
|
|
72
|
+
const result = await createIssue(title, body, labels, opts.milestone);
|
|
73
|
+
issueNumber = result.number;
|
|
74
|
+
issueUrl = result.url;
|
|
75
|
+
action = 'created';
|
|
76
|
+
const updatedRaw = setFrontmatterField(raw, 'githubIssue', issueNumber);
|
|
77
|
+
await updateArtifact(projectDir, config, type, artifactId, updatedRaw);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Create new issue
|
|
82
|
+
const result = await createIssue(title, body, labels, opts.milestone);
|
|
83
|
+
issueNumber = result.number;
|
|
84
|
+
issueUrl = result.url;
|
|
85
|
+
action = 'created';
|
|
86
|
+
// Store issue number in artifact frontmatter
|
|
87
|
+
const updatedRaw = setFrontmatterField(raw, 'githubIssue', issueNumber);
|
|
88
|
+
await updateArtifact(projectDir, config, type, artifactId, updatedRaw);
|
|
89
|
+
}
|
|
90
|
+
return { issueNumber, issueUrl, action };
|
|
91
|
+
}
|
|
92
|
+
/** Collect all artifact IDs under an epic. */
|
|
93
|
+
async function collectEpicArtifacts(projectDir, config, epicId) {
|
|
94
|
+
const ids = [epicId];
|
|
95
|
+
const features = await listArtifacts(projectDir, config, 'feature');
|
|
96
|
+
const stories = await listArtifacts(projectDir, config, 'story');
|
|
97
|
+
const tasks = await listArtifacts(projectDir, config, 'task');
|
|
98
|
+
const epicFeatureIds = new Set();
|
|
99
|
+
for (const f of features) {
|
|
100
|
+
const data = await readArtifact(projectDir, config, 'feature', f.id);
|
|
101
|
+
if (data?.data.epicId === epicId) {
|
|
102
|
+
epicFeatureIds.add(f.id);
|
|
103
|
+
ids.push(f.id);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const epicStoryIds = new Set();
|
|
107
|
+
for (const s of stories) {
|
|
108
|
+
const data = await readArtifact(projectDir, config, 'story', s.id);
|
|
109
|
+
if (data?.data.featureId && epicFeatureIds.has(data.data.featureId)) {
|
|
110
|
+
epicStoryIds.add(s.id);
|
|
111
|
+
ids.push(s.id);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const t of tasks) {
|
|
115
|
+
const data = await readArtifact(projectDir, config, 'task', t.id);
|
|
116
|
+
const parentStory = data?.data.storyId;
|
|
117
|
+
const parentFeature = data?.data.featureId;
|
|
118
|
+
if ((parentStory && epicStoryIds.has(parentStory)) ||
|
|
119
|
+
(parentFeature && epicFeatureIds.has(parentFeature))) {
|
|
120
|
+
ids.push(t.id);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return ids;
|
|
124
|
+
}
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Command registration
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
export function registerGitHubCommand(program) {
|
|
129
|
+
const github = program
|
|
130
|
+
.command('github')
|
|
131
|
+
.description('Sync planning artifacts with GitHub Issues');
|
|
132
|
+
// --- planr github push ---
|
|
133
|
+
github
|
|
134
|
+
.command('push')
|
|
135
|
+
.description('Push artifacts to GitHub Issues')
|
|
136
|
+
.argument('[artifactId]', 'artifact ID to push (e.g., TASK-001)')
|
|
137
|
+
.option('--epic <epicId>', 'push all artifacts under an epic')
|
|
138
|
+
.option('--all', 'push all artifacts across all types')
|
|
139
|
+
.action(async (artifactId, opts) => {
|
|
140
|
+
const projectDir = program.opts().projectDir;
|
|
141
|
+
const config = await loadConfig(projectDir);
|
|
142
|
+
// Verify GitHub repo
|
|
143
|
+
let repoInfo;
|
|
144
|
+
try {
|
|
145
|
+
repoInfo = await verifyGitHubRepo();
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
logger.error(e.message);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
logger.heading(`GitHub Push — ${repoInfo.owner}/${repoInfo.repo}`);
|
|
152
|
+
console.log('');
|
|
153
|
+
let artifactIds = [];
|
|
154
|
+
if (opts.all) {
|
|
155
|
+
// Push everything
|
|
156
|
+
const types = ['epic', 'feature', 'story', 'task', 'quick'];
|
|
157
|
+
for (const type of types) {
|
|
158
|
+
const artifacts = await listArtifacts(projectDir, config, type);
|
|
159
|
+
for (const a of artifacts)
|
|
160
|
+
artifactIds.push(a.id);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else if (opts.epic) {
|
|
164
|
+
// Push all under epic, create milestone
|
|
165
|
+
const epic = await readArtifact(projectDir, config, 'epic', opts.epic);
|
|
166
|
+
if (!epic) {
|
|
167
|
+
logger.error(`Epic not found: ${opts.epic}`);
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
const milestoneTitle = `${opts.epic}: ${epic.data.title}`;
|
|
171
|
+
try {
|
|
172
|
+
await ensureMilestone(milestoneTitle);
|
|
173
|
+
logger.success(`Milestone: ${milestoneTitle}`);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
logger.warn('Could not create milestone, pushing without it');
|
|
177
|
+
}
|
|
178
|
+
artifactIds = await collectEpicArtifacts(projectDir, config, opts.epic);
|
|
179
|
+
}
|
|
180
|
+
else if (artifactId) {
|
|
181
|
+
artifactIds = [artifactId];
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
logger.error('Provide an artifact ID, --epic, or --all');
|
|
185
|
+
logger.dim('Usage: planr github push TASK-001');
|
|
186
|
+
logger.dim(' planr github push --epic EPIC-001');
|
|
187
|
+
logger.dim(' planr github push --all');
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
if (artifactIds.length === 0) {
|
|
191
|
+
logger.warn('No artifacts found to push');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
logger.dim(`Pushing ${artifactIds.length} artifact${artifactIds.length !== 1 ? 's' : ''}...`);
|
|
195
|
+
console.log('');
|
|
196
|
+
let created = 0;
|
|
197
|
+
let updated = 0;
|
|
198
|
+
const milestoneTitle = opts.epic
|
|
199
|
+
? `${opts.epic}: ${(await readArtifact(projectDir, config, 'epic', opts.epic))?.data.title}`
|
|
200
|
+
: undefined;
|
|
201
|
+
for (const id of artifactIds) {
|
|
202
|
+
try {
|
|
203
|
+
const result = await pushSingleArtifact(projectDir, config, id, {
|
|
204
|
+
milestone: milestoneTitle,
|
|
205
|
+
});
|
|
206
|
+
if (result) {
|
|
207
|
+
const icon = result.action === 'created' ? chalk.green('+') : chalk.yellow('~');
|
|
208
|
+
console.log(` ${icon} ${id} → #${result.issueNumber} (${result.action})`);
|
|
209
|
+
if (result.action === 'created')
|
|
210
|
+
created++;
|
|
211
|
+
else
|
|
212
|
+
updated++;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (e) {
|
|
216
|
+
logger.error(` Failed to push ${id}: ${e.message}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
console.log('');
|
|
220
|
+
logger.success(`Done: ${created} created, ${updated} updated`);
|
|
221
|
+
});
|
|
222
|
+
// --- planr github sync ---
|
|
223
|
+
github
|
|
224
|
+
.command('sync')
|
|
225
|
+
.description('Sync artifact status with GitHub Issues (bi-directional)')
|
|
226
|
+
.option('--direction <dir>', 'sync direction: pull (GitHub→local), push (local→GitHub), or both', 'both')
|
|
227
|
+
.action(async (opts) => {
|
|
228
|
+
const projectDir = program.opts().projectDir;
|
|
229
|
+
const config = await loadConfig(projectDir);
|
|
230
|
+
let repoInfo;
|
|
231
|
+
try {
|
|
232
|
+
repoInfo = await verifyGitHubRepo();
|
|
233
|
+
}
|
|
234
|
+
catch (e) {
|
|
235
|
+
logger.error(e.message);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
logger.heading(`GitHub Sync — ${repoInfo.owner}/${repoInfo.repo}`);
|
|
239
|
+
console.log('');
|
|
240
|
+
// Find all artifacts with githubIssue field
|
|
241
|
+
const types = ['epic', 'feature', 'story', 'task', 'quick'];
|
|
242
|
+
const linkedArtifacts = [];
|
|
243
|
+
for (const type of types) {
|
|
244
|
+
const artifacts = await listArtifacts(projectDir, config, type);
|
|
245
|
+
for (const a of artifacts) {
|
|
246
|
+
const data = await readArtifact(projectDir, config, type, a.id);
|
|
247
|
+
if (data?.data.githubIssue) {
|
|
248
|
+
linkedArtifacts.push({
|
|
249
|
+
id: a.id,
|
|
250
|
+
type,
|
|
251
|
+
issueNumber: data.data.githubIssue,
|
|
252
|
+
status: data.data.status || 'pending',
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (linkedArtifacts.length === 0) {
|
|
258
|
+
logger.warn('No artifacts linked to GitHub Issues. Run `planr github push` first.');
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
logger.dim(`Found ${linkedArtifacts.length} linked artifact${linkedArtifacts.length !== 1 ? 's' : ''}`);
|
|
262
|
+
console.log('');
|
|
263
|
+
let synced = 0;
|
|
264
|
+
const conflicts = [];
|
|
265
|
+
for (const artifact of linkedArtifacts) {
|
|
266
|
+
try {
|
|
267
|
+
const issue = await getIssue(artifact.issueNumber);
|
|
268
|
+
const remoteStatus = issueStateToStatus(issue.state);
|
|
269
|
+
const localStatus = artifact.status;
|
|
270
|
+
if (remoteStatus === localStatus) {
|
|
271
|
+
// Already in sync
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (opts.direction === 'pull') {
|
|
275
|
+
// GitHub → local
|
|
276
|
+
await updateLocalStatus(projectDir, config, artifact.type, artifact.id, remoteStatus);
|
|
277
|
+
console.log(` ${chalk.blue('←')} ${artifact.id}: ${chalk.dim(localStatus)} → ${chalk.green(remoteStatus)} (from #${artifact.issueNumber})`);
|
|
278
|
+
synced++;
|
|
279
|
+
}
|
|
280
|
+
else if (opts.direction === 'push') {
|
|
281
|
+
// Local → GitHub
|
|
282
|
+
const targetState = statusToIssueState(localStatus);
|
|
283
|
+
if (issue.state !== targetState) {
|
|
284
|
+
await updateIssue(artifact.issueNumber, { state: targetState });
|
|
285
|
+
}
|
|
286
|
+
console.log(` ${chalk.yellow('→')} ${artifact.id}: #${artifact.issueNumber} ${chalk.dim(issue.state)} → ${chalk.green(targetState)}`);
|
|
287
|
+
synced++;
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
// Both — detect conflicts
|
|
291
|
+
conflicts.push({
|
|
292
|
+
id: artifact.id,
|
|
293
|
+
localStatus,
|
|
294
|
+
remoteState: issue.state,
|
|
295
|
+
issueNumber: artifact.issueNumber,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
catch (e) {
|
|
300
|
+
logger.error(` Failed to sync ${artifact.id}: ${e.message}`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// Handle conflicts for bi-directional sync
|
|
304
|
+
if (conflicts.length > 0) {
|
|
305
|
+
console.log('');
|
|
306
|
+
logger.heading('Conflicts detected');
|
|
307
|
+
console.log('');
|
|
308
|
+
for (const conflict of conflicts) {
|
|
309
|
+
const remoteStatus = issueStateToStatus(conflict.remoteState);
|
|
310
|
+
console.log(` ${chalk.red('!')} ${conflict.id} — local: ${chalk.yellow(conflict.localStatus)}, GitHub #${conflict.issueNumber}: ${chalk.cyan(conflict.remoteState)} (${remoteStatus})`);
|
|
311
|
+
const action = await promptSelect(` Resolve ${conflict.id}:`, [
|
|
312
|
+
{
|
|
313
|
+
name: `Use GitHub status (${remoteStatus})`,
|
|
314
|
+
value: 'pull',
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
name: `Use local status (${conflict.localStatus})`,
|
|
318
|
+
value: 'push',
|
|
319
|
+
},
|
|
320
|
+
{ name: 'Skip', value: 'skip' },
|
|
321
|
+
]);
|
|
322
|
+
if (action === 'pull') {
|
|
323
|
+
await updateLocalStatus(projectDir, config, findArtifactTypeById(conflict.id) || 'task', conflict.id, remoteStatus);
|
|
324
|
+
console.log(` ${chalk.blue('←')} Updated local to ${remoteStatus}`);
|
|
325
|
+
synced++;
|
|
326
|
+
}
|
|
327
|
+
else if (action === 'push') {
|
|
328
|
+
const targetState = statusToIssueState(conflict.localStatus);
|
|
329
|
+
await updateIssue(conflict.issueNumber, { state: targetState });
|
|
330
|
+
console.log(` ${chalk.yellow('→')} Updated GitHub to ${targetState}`);
|
|
331
|
+
synced++;
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
console.log(` ${chalk.dim('Skipped')}`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
console.log('');
|
|
339
|
+
if (synced > 0) {
|
|
340
|
+
logger.success(`Synced ${synced} artifact${synced !== 1 ? 's' : ''}`);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
logger.success('All artifacts are in sync');
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
// --- planr github status ---
|
|
347
|
+
github
|
|
348
|
+
.command('status')
|
|
349
|
+
.description('Show sync status of all linked artifacts')
|
|
350
|
+
.action(async () => {
|
|
351
|
+
const projectDir = program.opts().projectDir;
|
|
352
|
+
const config = await loadConfig(projectDir);
|
|
353
|
+
try {
|
|
354
|
+
await verifyGitHubRepo();
|
|
355
|
+
}
|
|
356
|
+
catch (e) {
|
|
357
|
+
logger.error(e.message);
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
logger.heading('GitHub Sync Status');
|
|
361
|
+
console.log('');
|
|
362
|
+
const types = ['epic', 'feature', 'story', 'task', 'quick'];
|
|
363
|
+
let linked = 0;
|
|
364
|
+
let unlinked = 0;
|
|
365
|
+
console.log(` ${chalk.dim('Artifact'.padEnd(14))} ${chalk.dim('Status'.padEnd(14))} ${chalk.dim('Issue'.padEnd(10))} ${chalk.dim('State')}`);
|
|
366
|
+
console.log(` ${'─'.repeat(50)}`);
|
|
367
|
+
for (const type of types) {
|
|
368
|
+
const artifacts = await listArtifacts(projectDir, config, type);
|
|
369
|
+
for (const a of artifacts) {
|
|
370
|
+
const data = await readArtifact(projectDir, config, type, a.id);
|
|
371
|
+
const status = data?.data.status || 'pending';
|
|
372
|
+
const issueNumber = data?.data.githubIssue;
|
|
373
|
+
if (issueNumber) {
|
|
374
|
+
let issueState = '';
|
|
375
|
+
try {
|
|
376
|
+
const issue = await getIssue(issueNumber);
|
|
377
|
+
issueState = issue.state;
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
issueState = 'error';
|
|
381
|
+
}
|
|
382
|
+
const inSync = issueStateToStatus(issueState) === status ||
|
|
383
|
+
statusToIssueState(status) === issueState;
|
|
384
|
+
const syncIcon = inSync ? chalk.green('✓') : chalk.red('✗');
|
|
385
|
+
console.log(` ${a.id.padEnd(14)} ${status.padEnd(14)} #${String(issueNumber).padEnd(8)} ${issueState} ${syncIcon}`);
|
|
386
|
+
linked++;
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
console.log(` ${a.id.padEnd(14)} ${status.padEnd(14)} ${chalk.dim('—'.padEnd(10))} ${chalk.dim('not linked')}`);
|
|
390
|
+
unlinked++;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
console.log(` ${'─'.repeat(50)}`);
|
|
395
|
+
console.log('');
|
|
396
|
+
console.log(` Linked: ${linked}, Unlinked: ${unlinked}`);
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
// ---------------------------------------------------------------------------
|
|
400
|
+
// Local status update
|
|
401
|
+
// ---------------------------------------------------------------------------
|
|
402
|
+
async function updateLocalStatus(projectDir, config, type, id, newStatus) {
|
|
403
|
+
const raw = await readArtifactRaw(projectDir, config, type, id);
|
|
404
|
+
if (!raw)
|
|
405
|
+
return;
|
|
406
|
+
const { data, content } = parseMarkdown(raw);
|
|
407
|
+
data.status = newStatus;
|
|
408
|
+
data.updated = new Date().toISOString().split('T')[0];
|
|
409
|
+
const updated = toMarkdownWithFrontmatter(data, content);
|
|
410
|
+
await updateArtifact(projectDir, config, type, id, updated);
|
|
411
|
+
}
|
|
412
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/cli/commands/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8BzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,QA2CnD"}
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import chalk from 'chalk';
|
|
15
|
-
import { buildEpicPrompt, buildFeaturesPrompt, buildStoriesPrompt,
|
|
16
|
-
import { aiEpicResponseSchema, aiFeaturesResponseSchema, aiStoriesResponseSchema,
|
|
15
|
+
import { buildEpicPrompt, buildFeaturesPrompt, buildStoriesPrompt, } from '../../ai/prompts/prompt-builder.js';
|
|
16
|
+
import { aiEpicResponseSchema, aiFeaturesResponseSchema, aiStoriesResponseSchema, } from '../../ai/schemas/ai-response-schemas.js';
|
|
17
17
|
import { TOKEN_BUDGETS } from '../../ai/types.js';
|
|
18
18
|
import { generateStreamingJSON, getAIProvider, isAIConfigured } from '../../services/ai-service.js';
|
|
19
19
|
import { addChildReference, createArtifact, getArtifactDir, listArtifacts, readArtifact, readArtifactRaw, resolveArtifactFilename, } from '../../services/artifact-service.js';
|
|
@@ -39,8 +39,8 @@ export function registerPlanCommand(program) {
|
|
|
39
39
|
const provider = await getAIProvider(config);
|
|
40
40
|
try {
|
|
41
41
|
if (opts.story) {
|
|
42
|
-
// Start from story → generate tasks
|
|
43
|
-
await
|
|
42
|
+
// Start from story → generate tasks (find parent feature and generate at feature level)
|
|
43
|
+
await generateTasksForSingleStory(projectDir, config, provider, opts.story);
|
|
44
44
|
}
|
|
45
45
|
else if (opts.feature) {
|
|
46
46
|
// Start from feature → stories → tasks
|
|
@@ -205,26 +205,26 @@ async function planFromFeature(projectDir, config, provider, featureId) {
|
|
|
205
205
|
await addChildReference(projectDir, config, 'feature', featureId, 'story', id, story.title);
|
|
206
206
|
logger.success(`Created ${id}: ${story.title}`);
|
|
207
207
|
}
|
|
208
|
-
// Step 4: Generate
|
|
209
|
-
|
|
210
|
-
await generateTasksForStory(projectDir, config, provider, storyId);
|
|
211
|
-
}
|
|
208
|
+
// Step 4: Generate one task list per feature (all stories + full context)
|
|
209
|
+
await generateTasksForFeature(projectDir, config, provider, featureId, storyIds);
|
|
212
210
|
}
|
|
213
|
-
async function
|
|
214
|
-
const {
|
|
211
|
+
async function generateTasksForFeature(projectDir, config, provider, featureId, storyIds) {
|
|
212
|
+
const { gatherFeatureArtifacts } = await import('../../services/artifact-gathering.js');
|
|
213
|
+
const { buildTasksPrompt } = await import('../../ai/prompts/prompt-builder.js');
|
|
214
|
+
const { aiTasksResponseSchema } = await import('../../ai/schemas/ai-response-schemas.js');
|
|
215
215
|
let ctx;
|
|
216
216
|
try {
|
|
217
|
-
ctx = await
|
|
217
|
+
ctx = await gatherFeatureArtifacts(projectDir, config, featureId);
|
|
218
218
|
}
|
|
219
219
|
catch {
|
|
220
|
-
logger.error(`
|
|
220
|
+
logger.error(`Feature ${featureId} not found.`);
|
|
221
221
|
return;
|
|
222
222
|
}
|
|
223
|
-
logger.dim(`\n[4/4] Generating tasks for ${
|
|
224
|
-
ctx.scope = { type: '
|
|
223
|
+
logger.dim(`\n[4/4] Generating tasks for ${featureId} (${ctx.stories.length} stories)...`);
|
|
224
|
+
ctx.scope = { type: 'feature', id: featureId };
|
|
225
225
|
const taskMessages = buildTasksPrompt(ctx);
|
|
226
226
|
const { result } = await generateStreamingJSON(provider, taskMessages, aiTasksResponseSchema, {
|
|
227
|
-
maxTokens: TOKEN_BUDGETS.
|
|
227
|
+
maxTokens: TOKEN_BUDGETS.taskFeature,
|
|
228
228
|
});
|
|
229
229
|
const tasks = result.tasks.map((tg) => ({
|
|
230
230
|
id: tg.id,
|
|
@@ -237,7 +237,7 @@ async function generateTasksForStory(projectDir, config, provider, storyId) {
|
|
|
237
237
|
subtasks: [],
|
|
238
238
|
})),
|
|
239
239
|
}));
|
|
240
|
-
const
|
|
240
|
+
const featureFilename = await resolveArtifactFilename(projectDir, config, 'feature', featureId);
|
|
241
241
|
// Build artifact sources for traceability
|
|
242
242
|
const artifactSources = [];
|
|
243
243
|
for (const s of ctx.stories) {
|
|
@@ -257,15 +257,84 @@ async function generateTasksForStory(projectDir, config, provider, storyId) {
|
|
|
257
257
|
}
|
|
258
258
|
const { id } = await createArtifact(projectDir, config, 'task', 'tasks/task-list.md.hbs', {
|
|
259
259
|
title: result.title,
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
featureId,
|
|
261
|
+
featureFilename,
|
|
262
262
|
tasks,
|
|
263
263
|
artifactSources,
|
|
264
264
|
acceptanceCriteriaMapping: result.acceptanceCriteriaMapping,
|
|
265
265
|
relevantFiles: result.relevantFiles,
|
|
266
266
|
});
|
|
267
267
|
const total = tasks.reduce((sum, t) => sum + t.subtasks.length + 1, 0);
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
// Link task list from each story
|
|
269
|
+
for (const sId of storyIds) {
|
|
270
|
+
await addChildReference(projectDir, config, 'story', sId, 'task', id, result.title);
|
|
271
|
+
}
|
|
272
|
+
logger.success(`Created ${id}: ${result.title} (${total} tasks from ${ctx.stories.length} stories)`);
|
|
273
|
+
}
|
|
274
|
+
async function generateTasksForSingleStory(projectDir, config, provider, storyId) {
|
|
275
|
+
// Find parent feature and generate tasks at feature level
|
|
276
|
+
const storyData = await readArtifact(projectDir, config, 'story', storyId);
|
|
277
|
+
if (!storyData) {
|
|
278
|
+
logger.error(`Story ${storyId} not found.`);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const featureId = storyData.data.featureId;
|
|
282
|
+
if (featureId) {
|
|
283
|
+
logger.dim(`Story ${storyId} belongs to ${featureId} — generating tasks at feature level.`);
|
|
284
|
+
await generateTasksForFeature(projectDir, config, provider, featureId, [storyId]);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
// Orphan story — fall back to story-level gathering
|
|
288
|
+
const { gatherStoryArtifacts } = await import('../../services/artifact-gathering.js');
|
|
289
|
+
const { buildTasksPrompt } = await import('../../ai/prompts/prompt-builder.js');
|
|
290
|
+
const { aiTasksResponseSchema } = await import('../../ai/schemas/ai-response-schemas.js');
|
|
291
|
+
const ctx = await gatherStoryArtifacts(projectDir, config, storyId);
|
|
292
|
+
logger.dim(`\nGenerating tasks for ${storyId}...`);
|
|
293
|
+
ctx.scope = { type: 'story', id: storyId };
|
|
294
|
+
const taskMessages = buildTasksPrompt(ctx);
|
|
295
|
+
const { result } = await generateStreamingJSON(provider, taskMessages, aiTasksResponseSchema, {
|
|
296
|
+
maxTokens: TOKEN_BUDGETS.plan,
|
|
297
|
+
});
|
|
298
|
+
const tasks = result.tasks.map((tg) => ({
|
|
299
|
+
id: tg.id,
|
|
300
|
+
title: tg.title,
|
|
301
|
+
status: 'pending',
|
|
302
|
+
subtasks: (tg.subtasks || []).map((st) => ({
|
|
303
|
+
id: st.id,
|
|
304
|
+
title: st.title,
|
|
305
|
+
status: 'pending',
|
|
306
|
+
subtasks: [],
|
|
307
|
+
})),
|
|
308
|
+
}));
|
|
309
|
+
const storyFilename = await resolveArtifactFilename(projectDir, config, 'story', storyId);
|
|
310
|
+
const artifactSources = [];
|
|
311
|
+
for (const s of ctx.stories) {
|
|
312
|
+
artifactSources.push({
|
|
313
|
+
type: 'User Story',
|
|
314
|
+
path: `${config.outputPaths.agile}/stories/${s.id}`,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
for (const g of ctx.gherkinScenarios) {
|
|
318
|
+
artifactSources.push({
|
|
319
|
+
type: 'Gherkin',
|
|
320
|
+
path: `${config.outputPaths.agile}/stories/${g.storyId}-gherkin.feature`,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
for (const a of ctx.adrs) {
|
|
324
|
+
artifactSources.push({ type: 'ADR', path: `${config.outputPaths.agile}/adrs/${a.id}` });
|
|
325
|
+
}
|
|
326
|
+
const { id } = await createArtifact(projectDir, config, 'task', 'tasks/task-list.md.hbs', {
|
|
327
|
+
title: result.title,
|
|
328
|
+
storyId,
|
|
329
|
+
storyFilename,
|
|
330
|
+
tasks,
|
|
331
|
+
artifactSources,
|
|
332
|
+
acceptanceCriteriaMapping: result.acceptanceCriteriaMapping,
|
|
333
|
+
relevantFiles: result.relevantFiles,
|
|
334
|
+
});
|
|
335
|
+
const total = tasks.reduce((sum, t) => sum + t.subtasks.length + 1, 0);
|
|
336
|
+
await addChildReference(projectDir, config, 'story', storyId, 'task', id, result.title);
|
|
337
|
+
logger.success(`Created ${id}: ${result.title} (${total} tasks)`);
|
|
338
|
+
}
|
|
270
339
|
}
|
|
271
340
|
//# sourceMappingURL=plan.js.map
|