openplanr 0.1.0 → 0.2.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/dist/agents/agent-factory.d.ts +7 -0
- package/dist/agents/agent-factory.d.ts.map +1 -0
- package/dist/agents/agent-factory.js +22 -0
- package/dist/agents/agent-factory.js.map +1 -0
- package/dist/agents/claude-agent.d.ts +13 -0
- package/dist/agents/claude-agent.d.ts.map +1 -0
- package/dist/agents/claude-agent.js +48 -0
- package/dist/agents/claude-agent.js.map +1 -0
- package/dist/agents/codex-agent.d.ts +13 -0
- package/dist/agents/codex-agent.d.ts.map +1 -0
- package/dist/agents/codex-agent.js +47 -0
- package/dist/agents/codex-agent.js.map +1 -0
- package/dist/agents/cursor-agent.d.ts +13 -0
- package/dist/agents/cursor-agent.d.ts.map +1 -0
- package/dist/agents/cursor-agent.js +40 -0
- package/dist/agents/cursor-agent.js.map +1 -0
- package/dist/agents/implementation-bridge.d.ts +21 -0
- package/dist/agents/implementation-bridge.d.ts.map +1 -0
- package/dist/agents/implementation-bridge.js +173 -0
- package/dist/agents/implementation-bridge.js.map +1 -0
- package/dist/agents/index.d.ts +6 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +5 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/prompt-composer.d.ts +30 -0
- package/dist/agents/prompt-composer.d.ts.map +1 -0
- package/dist/agents/prompt-composer.js +81 -0
- package/dist/agents/prompt-composer.js.map +1 -0
- package/dist/agents/task-parser.d.ts +38 -0
- package/dist/agents/task-parser.d.ts.map +1 -0
- package/dist/agents/task-parser.js +83 -0
- package/dist/agents/task-parser.js.map +1 -0
- package/dist/agents/types.d.ts +23 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +8 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/agents/utils.d.ts +9 -0
- package/dist/agents/utils.d.ts.map +1 -0
- package/dist/agents/utils.js +21 -0
- package/dist/agents/utils.js.map +1 -0
- package/dist/ai/codebase/context-builder.d.ts +31 -0
- package/dist/ai/codebase/context-builder.d.ts.map +1 -0
- package/dist/ai/codebase/context-builder.js +93 -0
- package/dist/ai/codebase/context-builder.js.map +1 -0
- package/dist/ai/codebase/file-reader.d.ts +22 -0
- package/dist/ai/codebase/file-reader.d.ts.map +1 -0
- package/dist/ai/codebase/file-reader.js +111 -0
- package/dist/ai/codebase/file-reader.js.map +1 -0
- package/dist/ai/codebase/index.d.ts +5 -0
- package/dist/ai/codebase/index.d.ts.map +1 -0
- package/dist/ai/codebase/index.js +5 -0
- package/dist/ai/codebase/index.js.map +1 -0
- package/dist/ai/codebase/stack-detector.d.ts +18 -0
- package/dist/ai/codebase/stack-detector.d.ts.map +1 -0
- package/dist/ai/codebase/stack-detector.js +147 -0
- package/dist/ai/codebase/stack-detector.js.map +1 -0
- package/dist/ai/codebase/tree-generator.d.ts +8 -0
- package/dist/ai/codebase/tree-generator.d.ts.map +1 -0
- package/dist/ai/codebase/tree-generator.js +85 -0
- package/dist/ai/codebase/tree-generator.js.map +1 -0
- package/dist/ai/errors.d.ts +22 -0
- package/dist/ai/errors.d.ts.map +1 -0
- package/dist/ai/errors.js +70 -0
- package/dist/ai/errors.js.map +1 -0
- package/dist/ai/index.d.ts +11 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +10 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/prompts/prompt-builder.d.ts +42 -0
- package/dist/ai/prompts/prompt-builder.d.ts.map +1 -0
- package/dist/ai/prompts/prompt-builder.js +96 -0
- package/dist/ai/prompts/prompt-builder.js.map +1 -0
- package/dist/ai/prompts/system-prompts.d.ts +13 -0
- package/dist/ai/prompts/system-prompts.d.ts.map +1 -0
- package/dist/ai/prompts/system-prompts.js +115 -0
- package/dist/ai/prompts/system-prompts.js.map +1 -0
- package/dist/ai/provider-factory.d.ts +10 -0
- package/dist/ai/provider-factory.d.ts.map +1 -0
- package/dist/ai/provider-factory.js +33 -0
- package/dist/ai/provider-factory.js.map +1 -0
- package/dist/ai/providers/anthropic-provider.d.ts +22 -0
- package/dist/ai/providers/anthropic-provider.d.ts.map +1 -0
- package/dist/ai/providers/anthropic-provider.js +82 -0
- package/dist/ai/providers/anthropic-provider.js.map +1 -0
- package/dist/ai/providers/ollama-provider.d.ts +13 -0
- package/dist/ai/providers/ollama-provider.d.ts.map +1 -0
- package/dist/ai/providers/ollama-provider.js +16 -0
- package/dist/ai/providers/ollama-provider.js.map +1 -0
- package/dist/ai/providers/openai-provider.d.ts +17 -0
- package/dist/ai/providers/openai-provider.d.ts.map +1 -0
- package/dist/ai/providers/openai-provider.js +58 -0
- package/dist/ai/providers/openai-provider.js.map +1 -0
- package/dist/ai/schemas/ai-response-schemas.d.ts +422 -0
- package/dist/ai/schemas/ai-response-schemas.d.ts.map +1 -0
- package/dist/ai/schemas/ai-response-schemas.js +86 -0
- package/dist/ai/schemas/ai-response-schemas.js.map +1 -0
- package/dist/ai/types.d.ts +40 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +16 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/cli/commands/config.d.ts +8 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +112 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/epic.d.ts +7 -0
- package/dist/cli/commands/epic.d.ts.map +1 -1
- package/dist/cli/commands/epic.js +161 -31
- package/dist/cli/commands/epic.js.map +1 -1
- package/dist/cli/commands/feature.d.ts +6 -0
- package/dist/cli/commands/feature.d.ts.map +1 -1
- package/dist/cli/commands/feature.js +143 -30
- package/dist/cli/commands/feature.js.map +1 -1
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +48 -6
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/plan.d.ts +15 -0
- package/dist/cli/commands/plan.d.ts.map +1 -0
- package/dist/cli/commands/plan.js +259 -0
- package/dist/cli/commands/plan.js.map +1 -0
- package/dist/cli/commands/refine.d.ts +9 -0
- package/dist/cli/commands/refine.d.ts.map +1 -0
- package/dist/cli/commands/refine.js +81 -0
- package/dist/cli/commands/refine.js.map +1 -0
- package/dist/cli/commands/story.d.ts +6 -0
- package/dist/cli/commands/story.d.ts.map +1 -1
- package/dist/cli/commands/story.js +172 -43
- package/dist/cli/commands/story.js.map +1 -1
- package/dist/cli/commands/sync.d.ts +12 -0
- package/dist/cli/commands/sync.d.ts.map +1 -0
- package/dist/cli/commands/sync.js +226 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/commands/task.d.ts +9 -0
- package/dist/cli/commands/task.d.ts.map +1 -1
- package/dist/cli/commands/task.js +348 -35
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/index.js +10 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/models/schema.d.ts +41 -0
- package/dist/models/schema.d.ts.map +1 -1
- package/dist/models/schema.js +9 -0
- package/dist/models/schema.js.map +1 -1
- package/dist/models/types.d.ts +9 -0
- package/dist/models/types.d.ts.map +1 -1
- package/dist/services/ai-service.d.ts +40 -0
- package/dist/services/ai-service.d.ts.map +1 -0
- package/dist/services/ai-service.js +150 -0
- package/dist/services/ai-service.js.map +1 -0
- package/dist/services/artifact-gathering.d.ts +49 -0
- package/dist/services/artifact-gathering.d.ts.map +1 -0
- package/dist/services/artifact-gathering.js +128 -0
- package/dist/services/artifact-gathering.js.map +1 -0
- package/dist/services/artifact-service.d.ts +47 -0
- package/dist/services/artifact-service.d.ts.map +1 -1
- package/dist/services/artifact-service.js +166 -0
- package/dist/services/artifact-service.js.map +1 -1
- package/dist/services/credentials-service.d.ts +22 -0
- package/dist/services/credentials-service.d.ts.map +1 -0
- package/dist/services/credentials-service.js +58 -0
- package/dist/services/credentials-service.js.map +1 -0
- package/dist/services/id-service.d.ts.map +1 -1
- package/dist/services/id-service.js +8 -5
- package/dist/services/id-service.js.map +1 -1
- package/dist/services/prompt-service.d.ts +1 -0
- package/dist/services/prompt-service.d.ts.map +1 -1
- package/dist/services/prompt-service.js +4 -1
- package/dist/services/prompt-service.js.map +1 -1
- 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/checklists/agile-checklist.md.hbs +8 -8
- package/dist/templates/epics/epic.md.hbs +8 -2
- package/dist/templates/features/feature.md.hbs +3 -3
- package/dist/templates/rules/cursor/2001-agile-create-epic.mdc.hbs +1 -1
- package/dist/templates/rules/cursor/2002-agile-create-features.mdc.hbs +1 -1
- package/dist/templates/rules/cursor/2003-agile-create-user-story.mdc.hbs +1 -1
- package/dist/templates/stories/user-story.md.hbs +2 -2
- package/dist/templates/tasks/task-list.md.hbs +26 -3
- package/package.json +4 -2
- package/dist/templates/templates/adrs/adr-general.md.hbs +0 -46
- package/dist/templates/templates/checklists/agile-checklist.md.hbs +0 -49
- package/dist/templates/templates/epics/epic.md.hbs +0 -46
- package/dist/templates/templates/features/feature.md.hbs +0 -42
- package/dist/templates/templates/rules/claude/CLAUDE.md.hbs +0 -63
- package/dist/templates/templates/rules/codex/AGENTS.md.hbs +0 -28
- package/dist/templates/templates/rules/cursor/2000-agile-checklist.mdc.hbs +0 -33
- package/dist/templates/templates/rules/cursor/2001-agile-create-epic.mdc.hbs +0 -35
- package/dist/templates/templates/rules/cursor/2002-agile-create-features.mdc.hbs +0 -35
- package/dist/templates/templates/rules/cursor/2003-agile-create-user-story.mdc.hbs +0 -31
- package/dist/templates/templates/rules/cursor/2100-create-task-list.mdc.hbs +0 -36
- package/dist/templates/templates/rules/cursor/2101-implement-task-list.mdc.hbs +0 -28
- package/dist/templates/templates/stories/gherkin.feature.hbs +0 -13
- package/dist/templates/templates/stories/user-story.md.hbs +0 -28
- package/dist/templates/templates/tasks/task-list.md.hbs +0 -24
|
@@ -1,54 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr feature` command group.
|
|
3
|
+
*
|
|
4
|
+
* AI-powered by default: reads the parent epic and generates
|
|
5
|
+
* multiple features automatically. Use --manual for legacy mode.
|
|
6
|
+
*/
|
|
1
7
|
import { loadConfig } from '../../services/config-service.js';
|
|
2
|
-
import { createArtifact, listArtifacts, readArtifact } from '../../services/artifact-service.js';
|
|
3
|
-
import {
|
|
8
|
+
import { createArtifact, listArtifacts, readArtifact, readArtifactRaw, resolveArtifactFilename, addChildReference, } from '../../services/artifact-service.js';
|
|
9
|
+
import { isAIConfigured, getAIProvider, generateStreamingJSON } from '../../services/ai-service.js';
|
|
10
|
+
import { promptText, promptMultiText, promptConfirm } from '../../services/prompt-service.js';
|
|
11
|
+
import { buildFeaturesPrompt } from '../../ai/prompts/prompt-builder.js';
|
|
12
|
+
import { aiFeaturesResponseSchema } from '../../ai/schemas/ai-response-schemas.js';
|
|
4
13
|
import { logger } from '../../utils/logger.js';
|
|
14
|
+
import chalk from 'chalk';
|
|
5
15
|
export function registerFeatureCommand(program) {
|
|
6
16
|
const feature = program.command('feature').description('Manage features');
|
|
7
17
|
feature
|
|
8
18
|
.command('create')
|
|
9
|
-
.description('Create
|
|
19
|
+
.description('Create features from an epic')
|
|
10
20
|
.requiredOption('--epic <epicId>', 'parent epic ID (e.g., EPIC-001)')
|
|
11
21
|
.option('--title <title>', 'feature title')
|
|
22
|
+
.option('--count <n>', 'number of features to generate', parseInt)
|
|
23
|
+
.option('--manual', 'use manual interactive prompts instead of AI')
|
|
12
24
|
.action(async (opts) => {
|
|
13
25
|
const projectDir = program.opts().projectDir;
|
|
14
26
|
const config = await loadConfig(projectDir);
|
|
15
|
-
// Verify epic exists
|
|
16
27
|
const epicData = await readArtifact(projectDir, config, 'epic', opts.epic);
|
|
17
28
|
if (!epicData) {
|
|
18
29
|
logger.error(`Epic ${opts.epic} not found.`);
|
|
19
30
|
process.exit(1);
|
|
20
31
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
title,
|
|
32
|
-
epicId: opts.epic,
|
|
33
|
-
owner,
|
|
34
|
-
overview,
|
|
35
|
-
functionalRequirements,
|
|
36
|
-
dependencies,
|
|
37
|
-
technicalConsiderations,
|
|
38
|
-
risks,
|
|
39
|
-
successMetrics,
|
|
40
|
-
storyIds: [],
|
|
41
|
-
});
|
|
42
|
-
logger.success(`Created feature ${id}: ${title}`);
|
|
43
|
-
logger.dim(` ${filePath}`);
|
|
44
|
-
logger.dim('');
|
|
45
|
-
logger.dim(`Next: planr story create --feature ${id}`);
|
|
32
|
+
const useAI = !opts.manual && isAIConfigured(config);
|
|
33
|
+
if (useAI) {
|
|
34
|
+
await createFeaturesWithAI(projectDir, config, opts.epic, opts.count);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
if (!opts.manual && !isAIConfigured(config)) {
|
|
38
|
+
logger.warn('AI not configured. Using manual mode.');
|
|
39
|
+
}
|
|
40
|
+
await createFeatureManually(projectDir, config, opts);
|
|
41
|
+
}
|
|
46
42
|
});
|
|
47
43
|
feature
|
|
48
44
|
.command('list')
|
|
49
45
|
.description('List features')
|
|
50
46
|
.option('--epic <epicId>', 'filter by epic ID')
|
|
51
|
-
.action(async (
|
|
47
|
+
.action(async () => {
|
|
52
48
|
const projectDir = program.opts().projectDir;
|
|
53
49
|
const config = await loadConfig(projectDir);
|
|
54
50
|
const features = await listArtifacts(projectDir, config, 'feature');
|
|
@@ -62,4 +58,121 @@ export function registerFeatureCommand(program) {
|
|
|
62
58
|
}
|
|
63
59
|
});
|
|
64
60
|
}
|
|
61
|
+
async function createFeaturesWithAI(projectDir, config, epicId, featureCount) {
|
|
62
|
+
logger.heading(`Create Features (AI-powered from ${epicId})`);
|
|
63
|
+
const epicRaw = await readArtifactRaw(projectDir, config, 'epic', epicId);
|
|
64
|
+
if (!epicRaw) {
|
|
65
|
+
logger.error(`Could not read epic ${epicId}.`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Find existing features for THIS epic (for dedup + warning)
|
|
69
|
+
const allFeatures = await listArtifacts(projectDir, config, 'feature');
|
|
70
|
+
const epicFeatures = [];
|
|
71
|
+
for (const f of allFeatures) {
|
|
72
|
+
const data = await readArtifact(projectDir, config, 'feature', f.id);
|
|
73
|
+
if (data && data.data.epicId === epicId) {
|
|
74
|
+
epicFeatures.push({ id: f.id, title: data.data.title || f.title });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (epicFeatures.length > 0) {
|
|
78
|
+
logger.warn(`${epicId} already has ${epicFeatures.length} feature(s):`);
|
|
79
|
+
for (const f of epicFeatures) {
|
|
80
|
+
console.log(chalk.dim(` ${f.id}: ${f.title}`));
|
|
81
|
+
}
|
|
82
|
+
const continueCreate = await promptConfirm('Generate additional features? (AI will avoid duplicates)', false);
|
|
83
|
+
if (!continueCreate) {
|
|
84
|
+
logger.info('Feature creation cancelled.');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const existingTitles = epicFeatures.map((f) => `${f.id}: ${f.title}`);
|
|
89
|
+
logger.dim('AI is generating features from the epic...');
|
|
90
|
+
try {
|
|
91
|
+
const provider = await getAIProvider(config);
|
|
92
|
+
const messages = buildFeaturesPrompt(epicRaw, existingTitles, featureCount);
|
|
93
|
+
const result = await generateStreamingJSON(provider, messages, aiFeaturesResponseSchema);
|
|
94
|
+
// Display generated features
|
|
95
|
+
console.log(chalk.dim('━'.repeat(50)));
|
|
96
|
+
result.features.forEach((feat, i) => {
|
|
97
|
+
console.log(chalk.bold(` ${i + 1}. ${feat.title}`));
|
|
98
|
+
console.log(chalk.dim(` ${feat.overview}`));
|
|
99
|
+
console.log(` Requirements: ${feat.functionalRequirements.length} items`);
|
|
100
|
+
});
|
|
101
|
+
console.log(chalk.dim('━'.repeat(50)));
|
|
102
|
+
const confirmAll = await promptConfirm(`Create all ${result.features.length} features?`, true);
|
|
103
|
+
if (!confirmAll) {
|
|
104
|
+
logger.info('Feature creation cancelled.');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Create each feature
|
|
108
|
+
const createdIds = [];
|
|
109
|
+
const epicFilename = await resolveArtifactFilename(projectDir, config, 'epic', epicId);
|
|
110
|
+
for (const feat of result.features) {
|
|
111
|
+
const { id, filePath } = await createArtifact(projectDir, config, 'feature', 'features/feature.md.hbs', {
|
|
112
|
+
title: feat.title,
|
|
113
|
+
epicId,
|
|
114
|
+
epicFilename,
|
|
115
|
+
owner: config.author || 'Engineering',
|
|
116
|
+
overview: feat.overview,
|
|
117
|
+
functionalRequirements: feat.functionalRequirements,
|
|
118
|
+
dependencies: feat.dependencies,
|
|
119
|
+
technicalConsiderations: feat.technicalConsiderations,
|
|
120
|
+
risks: feat.risks,
|
|
121
|
+
successMetrics: feat.successMetrics,
|
|
122
|
+
storyIds: [],
|
|
123
|
+
});
|
|
124
|
+
createdIds.push(id);
|
|
125
|
+
await addChildReference(projectDir, config, 'epic', epicId, 'feature', id, feat.title);
|
|
126
|
+
logger.success(`Created ${id}: ${feat.title}`);
|
|
127
|
+
logger.dim(` ${filePath}`);
|
|
128
|
+
}
|
|
129
|
+
logger.dim('');
|
|
130
|
+
logger.heading('Next steps:');
|
|
131
|
+
logger.dim(` 1. planr story create --feature ${createdIds[0]} — Create user stories`);
|
|
132
|
+
logger.dim(` 2. planr task create --story US-* — Generate implementation tasks`);
|
|
133
|
+
logger.dim(` 3. planr task implement TASK-* — Implement with your coding agent`);
|
|
134
|
+
logger.dim('');
|
|
135
|
+
logger.dim(` Or generate stories for all features at once:`);
|
|
136
|
+
logger.dim(` planr plan --epic ${epicId} — Auto-generate stories → tasks`);
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
const { AIError } = await import('../../ai/errors.js');
|
|
140
|
+
if (err instanceof AIError) {
|
|
141
|
+
logger.error(err.userMessage);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function createFeatureManually(projectDir, config, opts) {
|
|
149
|
+
logger.heading(`Create Feature (from ${opts.epic})`);
|
|
150
|
+
const title = opts.title || (await promptText('Feature title:'));
|
|
151
|
+
const owner = await promptText('Owner:', config.author);
|
|
152
|
+
const overview = await promptText('Overview:');
|
|
153
|
+
const functionalRequirements = await promptMultiText('Functional requirements', 'comma-separated');
|
|
154
|
+
const dependencies = await promptText('Dependencies:', 'None');
|
|
155
|
+
const technicalConsiderations = await promptText('Technical considerations:', 'None');
|
|
156
|
+
const risks = await promptText('Risks:', 'None');
|
|
157
|
+
const successMetrics = await promptText('Success metrics:');
|
|
158
|
+
const epicFilename = await resolveArtifactFilename(projectDir, config, 'epic', opts.epic);
|
|
159
|
+
const { id, filePath } = await createArtifact(projectDir, config, 'feature', 'features/feature.md.hbs', {
|
|
160
|
+
title,
|
|
161
|
+
epicId: opts.epic,
|
|
162
|
+
epicFilename,
|
|
163
|
+
owner,
|
|
164
|
+
overview,
|
|
165
|
+
functionalRequirements,
|
|
166
|
+
dependencies,
|
|
167
|
+
technicalConsiderations,
|
|
168
|
+
risks,
|
|
169
|
+
successMetrics,
|
|
170
|
+
storyIds: [],
|
|
171
|
+
});
|
|
172
|
+
await addChildReference(projectDir, config, 'epic', opts.epic, 'feature', id, title);
|
|
173
|
+
logger.success(`Created feature ${id}: ${title}`);
|
|
174
|
+
logger.dim(` ${filePath}`);
|
|
175
|
+
logger.dim('');
|
|
176
|
+
logger.dim(`Next: planr story create --feature ${id}`);
|
|
177
|
+
}
|
|
65
178
|
//# sourceMappingURL=feature.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature.js","sourceRoot":"","sources":["../../../src/cli/commands/feature.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"feature.js","sourceRoot":"","sources":["../../../src/cli/commands/feature.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr init` command.
|
|
3
|
+
*
|
|
4
|
+
* Initializes a new Planr project with directory structure, config,
|
|
5
|
+
* and optional AI provider setup.
|
|
6
|
+
*/
|
|
1
7
|
import { Command } from 'commander';
|
|
2
8
|
export declare function registerInitCommand(program: Command): void;
|
|
3
9
|
//# sourceMappingURL=init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,QA8FnD"}
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr init` command.
|
|
3
|
+
*
|
|
4
|
+
* Initializes a new Planr project with directory structure, config,
|
|
5
|
+
* and optional AI provider setup.
|
|
6
|
+
*/
|
|
1
7
|
import path from 'node:path';
|
|
2
8
|
import { createDefaultConfig, saveConfig } from '../../services/config-service.js';
|
|
3
9
|
import { createChecklist } from '../../services/checklist-service.js';
|
|
4
|
-
import {
|
|
5
|
-
import { fileExists } from '../../utils/fs.js';
|
|
10
|
+
import { saveCredential } from '../../services/credentials-service.js';
|
|
11
|
+
import { ensureDir, fileExists } from '../../utils/fs.js';
|
|
6
12
|
import { CONFIG_FILENAME, ARTIFACT_DIRS } from '../../utils/constants.js';
|
|
7
13
|
import { logger } from '../../utils/logger.js';
|
|
8
|
-
import { promptText, promptConfirm } from '../../services/prompt-service.js';
|
|
14
|
+
import { promptText, promptConfirm, promptSelect, promptSecret } from '../../services/prompt-service.js';
|
|
9
15
|
export function registerInitCommand(program) {
|
|
10
16
|
program
|
|
11
17
|
.command('init')
|
|
12
18
|
.description('Initialize Planr in the current project')
|
|
13
19
|
.option('--name <name>', 'project name')
|
|
20
|
+
.option('--no-ai', 'skip AI setup')
|
|
14
21
|
.action(async (opts) => {
|
|
15
22
|
const projectDir = program.opts().projectDir;
|
|
16
23
|
const configPath = path.join(projectDir, CONFIG_FILENAME);
|
|
@@ -23,27 +30,62 @@ export function registerInitCommand(program) {
|
|
|
23
30
|
}
|
|
24
31
|
const projectName = opts.name || (await promptText('Project name:', path.basename(projectDir)));
|
|
25
32
|
const config = createDefaultConfig(projectName);
|
|
33
|
+
// --- AI Provider Setup ---
|
|
34
|
+
if (opts.ai !== false) {
|
|
35
|
+
const enableAI = await promptConfirm('Enable AI-powered planning?', true);
|
|
36
|
+
if (enableAI) {
|
|
37
|
+
const provider = await promptSelect('AI provider:', [
|
|
38
|
+
{ name: 'Anthropic (Claude)', value: 'anthropic' },
|
|
39
|
+
{ name: 'OpenAI (GPT-4o)', value: 'openai' },
|
|
40
|
+
{ name: 'Ollama (Local — free, no API key)', value: 'ollama' },
|
|
41
|
+
]);
|
|
42
|
+
config.ai = { provider };
|
|
43
|
+
// Collect API key for cloud providers
|
|
44
|
+
if (provider === 'anthropic' || provider === 'openai') {
|
|
45
|
+
const keyHint = provider === 'anthropic' ? 'ANTHROPIC_API_KEY' : 'OPENAI_API_KEY';
|
|
46
|
+
const apiKey = await promptSecret(`API key (or press Enter to set ${keyHint} env var later):`);
|
|
47
|
+
if (apiKey.trim()) {
|
|
48
|
+
await saveCredential(provider, apiKey.trim());
|
|
49
|
+
logger.success(`API key saved to ~/.planr/credentials.json`);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
logger.dim(` No key provided. Set ${keyHint} env var or run \`planr config set-key ${provider}\`.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Coding agent preference
|
|
56
|
+
const agent = await promptSelect('Default coding agent:', [
|
|
57
|
+
{ name: 'Claude Code CLI', value: 'claude' },
|
|
58
|
+
{ name: 'Cursor', value: 'cursor' },
|
|
59
|
+
{ name: 'Codex', value: 'codex' },
|
|
60
|
+
]);
|
|
61
|
+
config.defaultAgent = agent;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
26
64
|
// Create directory structure
|
|
27
65
|
const agileDir = path.join(projectDir, config.outputPaths.agile);
|
|
28
66
|
for (const dir of Object.values(ARTIFACT_DIRS)) {
|
|
29
67
|
await ensureDir(path.join(agileDir, dir));
|
|
30
68
|
}
|
|
31
|
-
// Also create diagrams dir
|
|
32
69
|
await ensureDir(path.join(agileDir, 'diagrams'));
|
|
33
70
|
// Save config
|
|
34
71
|
await saveConfig(projectDir, config);
|
|
35
72
|
logger.success(`Created ${CONFIG_FILENAME}`);
|
|
36
73
|
// Create checklist
|
|
37
|
-
|
|
74
|
+
await createChecklist(projectDir, config);
|
|
38
75
|
logger.success(`Created agile development checklist`);
|
|
76
|
+
// Summary
|
|
39
77
|
logger.heading('Planr initialized!');
|
|
40
78
|
logger.info(`Project: ${projectName}`);
|
|
41
79
|
logger.info(`Artifacts: ${config.outputPaths.agile}/`);
|
|
80
|
+
if (config.ai) {
|
|
81
|
+
logger.info(`AI: ${config.ai.provider} (every command is AI-powered)`);
|
|
82
|
+
logger.info(`Agent: ${config.defaultAgent || 'claude'}`);
|
|
83
|
+
}
|
|
42
84
|
logger.dim('');
|
|
43
85
|
logger.dim('Next steps:');
|
|
44
86
|
logger.dim(' planr epic create — Create your first epic');
|
|
45
87
|
logger.dim(' planr rules generate — Generate AI agent rules');
|
|
46
|
-
logger.dim(' planr
|
|
88
|
+
logger.dim(' planr config show — View configuration');
|
|
47
89
|
});
|
|
48
90
|
}
|
|
49
91
|
//# sourceMappingURL=init.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr plan` command.
|
|
3
|
+
*
|
|
4
|
+
* Full agile planning flow in a single command:
|
|
5
|
+
* Epic → Features → User Stories → Tasks
|
|
6
|
+
*
|
|
7
|
+
* Can start from any level:
|
|
8
|
+
* --epic EPIC-001 → generates features → stories → tasks
|
|
9
|
+
* --feature FEAT-001 → generates stories → tasks
|
|
10
|
+
* --story US-001 → generates tasks
|
|
11
|
+
* (no flag) → creates epic first, then cascades
|
|
12
|
+
*/
|
|
13
|
+
import { Command } from 'commander';
|
|
14
|
+
export declare function registerPlanCommand(program: Command): void;
|
|
15
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4BpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,QAyCnD"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr plan` command.
|
|
3
|
+
*
|
|
4
|
+
* Full agile planning flow in a single command:
|
|
5
|
+
* Epic → Features → User Stories → Tasks
|
|
6
|
+
*
|
|
7
|
+
* Can start from any level:
|
|
8
|
+
* --epic EPIC-001 → generates features → stories → tasks
|
|
9
|
+
* --feature FEAT-001 → generates stories → tasks
|
|
10
|
+
* --story US-001 → generates tasks
|
|
11
|
+
* (no flag) → creates epic first, then cascades
|
|
12
|
+
*/
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { loadConfig } from '../../services/config-service.js';
|
|
15
|
+
import { createArtifact, listArtifacts, readArtifact, readArtifactRaw, getArtifactDir, resolveArtifactFilename, addChildReference, } from '../../services/artifact-service.js';
|
|
16
|
+
import { isAIConfigured, getAIProvider, generateStreamingJSON } from '../../services/ai-service.js';
|
|
17
|
+
import { promptText, promptConfirm } from '../../services/prompt-service.js';
|
|
18
|
+
import { renderTemplate } from '../../services/template-service.js';
|
|
19
|
+
import { writeFile } from '../../utils/fs.js';
|
|
20
|
+
import { buildEpicPrompt, buildFeaturesPrompt, buildStoriesPrompt, buildTasksPrompt } from '../../ai/prompts/prompt-builder.js';
|
|
21
|
+
import { aiEpicResponseSchema, aiFeaturesResponseSchema, aiStoriesResponseSchema, aiTasksResponseSchema, } from '../../ai/schemas/ai-response-schemas.js';
|
|
22
|
+
import { logger } from '../../utils/logger.js';
|
|
23
|
+
import chalk from 'chalk';
|
|
24
|
+
export function registerPlanCommand(program) {
|
|
25
|
+
program
|
|
26
|
+
.command('plan')
|
|
27
|
+
.description('Full agile planning flow: Epic → Features → Stories → Tasks')
|
|
28
|
+
.option('--epic <epicId>', 'start from an existing epic')
|
|
29
|
+
.option('--feature <featureId>', 'start from an existing feature')
|
|
30
|
+
.option('--story <storyId>', 'start from an existing story (generates tasks only)')
|
|
31
|
+
.action(async (opts) => {
|
|
32
|
+
const projectDir = program.opts().projectDir;
|
|
33
|
+
const config = await loadConfig(projectDir);
|
|
34
|
+
if (!isAIConfigured(config)) {
|
|
35
|
+
logger.error('AI must be configured for the plan command. Run `planr config set-provider`.');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
const provider = await getAIProvider(config);
|
|
39
|
+
try {
|
|
40
|
+
if (opts.story) {
|
|
41
|
+
// Start from story → generate tasks
|
|
42
|
+
await generateTasksForStory(projectDir, config, provider, opts.story);
|
|
43
|
+
}
|
|
44
|
+
else if (opts.feature) {
|
|
45
|
+
// Start from feature → stories → tasks
|
|
46
|
+
await planFromFeature(projectDir, config, provider, opts.feature);
|
|
47
|
+
}
|
|
48
|
+
else if (opts.epic) {
|
|
49
|
+
// Start from epic → features → stories → tasks
|
|
50
|
+
await planFromEpic(projectDir, config, provider, opts.epic);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// Full flow: create epic first
|
|
54
|
+
await planFromScratch(projectDir, config, provider);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
const { AIError } = await import('../../ai/errors.js');
|
|
59
|
+
if (err instanceof AIError) {
|
|
60
|
+
logger.error(err.userMessage);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async function planFromScratch(projectDir, config, provider) {
|
|
69
|
+
logger.heading('Full Agile Planning Flow');
|
|
70
|
+
logger.dim('Epic → Features → User Stories → Tasks\n');
|
|
71
|
+
// Step 1: Create Epic
|
|
72
|
+
const brief = await promptText('Describe your epic in a sentence or two:');
|
|
73
|
+
const existingEpics = await listArtifacts(projectDir, config, 'epic');
|
|
74
|
+
const existingTitles = existingEpics.map((e) => `${e.id}: ${e.title}`);
|
|
75
|
+
logger.dim('\n[1/4] Generating epic...');
|
|
76
|
+
const epicMessages = buildEpicPrompt(brief, existingTitles);
|
|
77
|
+
const epicData = await generateStreamingJSON(provider, epicMessages, aiEpicResponseSchema);
|
|
78
|
+
console.log(chalk.bold(`\n Epic: ${epicData.title}`));
|
|
79
|
+
console.log(chalk.dim(` ${epicData.solutionOverview}`));
|
|
80
|
+
const continueFlow = await promptConfirm('Save epic and continue planning?', true);
|
|
81
|
+
if (!continueFlow) {
|
|
82
|
+
logger.info('Planning cancelled.');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const epicCriteriaArray = Array.isArray(epicData.successCriteria)
|
|
86
|
+
? epicData.successCriteria
|
|
87
|
+
: [epicData.successCriteria];
|
|
88
|
+
const { id: epicId } = await createArtifact(projectDir, config, 'epic', 'epics/epic.md.hbs', {
|
|
89
|
+
...epicData,
|
|
90
|
+
successCriteria: epicCriteriaArray.join('; '),
|
|
91
|
+
successCriteriaList: epicCriteriaArray,
|
|
92
|
+
featureIds: [],
|
|
93
|
+
});
|
|
94
|
+
logger.success(`Created ${epicId}: ${epicData.title}`);
|
|
95
|
+
await planFromEpic(projectDir, config, provider, epicId);
|
|
96
|
+
}
|
|
97
|
+
async function planFromEpic(projectDir, config, provider, epicId) {
|
|
98
|
+
// Step 2: Generate Features
|
|
99
|
+
const epicRaw = await readArtifactRaw(projectDir, config, 'epic', epicId);
|
|
100
|
+
if (!epicRaw) {
|
|
101
|
+
logger.error(`Epic ${epicId} not found.`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const existingFeatures = await listArtifacts(projectDir, config, 'feature');
|
|
105
|
+
const existingFeatureTitles = existingFeatures.map((f) => `${f.id}: ${f.title}`);
|
|
106
|
+
logger.dim('\n[2/4] Generating features...');
|
|
107
|
+
const featureMessages = buildFeaturesPrompt(epicRaw, existingFeatureTitles);
|
|
108
|
+
const featureResult = await generateStreamingJSON(provider, featureMessages, aiFeaturesResponseSchema);
|
|
109
|
+
console.log(chalk.bold(`\n Generated ${featureResult.features.length} features:`));
|
|
110
|
+
featureResult.features.forEach((f, i) => {
|
|
111
|
+
console.log(chalk.dim(` ${i + 1}. ${f.title}`));
|
|
112
|
+
});
|
|
113
|
+
const continueFeatures = await promptConfirm(`Create all ${featureResult.features.length} features and continue?`, true);
|
|
114
|
+
if (!continueFeatures) {
|
|
115
|
+
logger.info('Planning paused after epic.');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const featureIds = [];
|
|
119
|
+
const epicFilename = await resolveArtifactFilename(projectDir, config, 'epic', epicId);
|
|
120
|
+
for (const feat of featureResult.features) {
|
|
121
|
+
const { id } = await createArtifact(projectDir, config, 'feature', 'features/feature.md.hbs', {
|
|
122
|
+
title: feat.title,
|
|
123
|
+
epicId,
|
|
124
|
+
epicFilename,
|
|
125
|
+
owner: config.author || 'Engineering',
|
|
126
|
+
overview: feat.overview,
|
|
127
|
+
functionalRequirements: feat.functionalRequirements,
|
|
128
|
+
dependencies: feat.dependencies,
|
|
129
|
+
technicalConsiderations: feat.technicalConsiderations,
|
|
130
|
+
risks: feat.risks,
|
|
131
|
+
successMetrics: feat.successMetrics,
|
|
132
|
+
storyIds: [],
|
|
133
|
+
});
|
|
134
|
+
featureIds.push(id);
|
|
135
|
+
await addChildReference(projectDir, config, 'epic', epicId, 'feature', id, feat.title);
|
|
136
|
+
logger.success(`Created ${id}: ${feat.title}`);
|
|
137
|
+
}
|
|
138
|
+
// Step 3+4: Stories and tasks for each feature
|
|
139
|
+
for (const featureId of featureIds) {
|
|
140
|
+
await planFromFeature(projectDir, config, provider, featureId);
|
|
141
|
+
}
|
|
142
|
+
// Final summary
|
|
143
|
+
logger.heading('\nPlanning Complete!');
|
|
144
|
+
const allFeatures = await listArtifacts(projectDir, config, 'feature');
|
|
145
|
+
const allStories = await listArtifacts(projectDir, config, 'story');
|
|
146
|
+
const allTasks = await listArtifacts(projectDir, config, 'task');
|
|
147
|
+
console.log(` Epic: ${epicId}`);
|
|
148
|
+
console.log(` Features: ${allFeatures.length}`);
|
|
149
|
+
console.log(` Stories: ${allStories.length}`);
|
|
150
|
+
console.log(` Tasks: ${allTasks.length}`);
|
|
151
|
+
logger.dim('');
|
|
152
|
+
logger.dim('Start implementing:');
|
|
153
|
+
logger.dim(' planr task implement TASK-001 --next');
|
|
154
|
+
logger.dim(' planr status');
|
|
155
|
+
}
|
|
156
|
+
async function planFromFeature(projectDir, config, provider, featureId) {
|
|
157
|
+
// Step 3: Generate Stories
|
|
158
|
+
const featureRaw = await readArtifactRaw(projectDir, config, 'feature', featureId);
|
|
159
|
+
if (!featureRaw) {
|
|
160
|
+
logger.error(`Feature ${featureId} not found.`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const featureData = await readArtifact(projectDir, config, 'feature', featureId);
|
|
164
|
+
const epicId = featureData?.data.epicId;
|
|
165
|
+
let epicRaw = '';
|
|
166
|
+
if (epicId) {
|
|
167
|
+
epicRaw = (await readArtifactRaw(projectDir, config, 'epic', epicId)) || '';
|
|
168
|
+
}
|
|
169
|
+
const existingStories = await listArtifacts(projectDir, config, 'story');
|
|
170
|
+
const existingStoryTitles = existingStories.map((s) => `${s.id}: ${s.title}`);
|
|
171
|
+
logger.dim(`\n[3/4] Generating stories for ${featureId}...`);
|
|
172
|
+
const storyMessages = buildStoriesPrompt(featureRaw, epicRaw, existingStoryTitles);
|
|
173
|
+
const storyResult = await generateStreamingJSON(provider, storyMessages, aiStoriesResponseSchema);
|
|
174
|
+
console.log(chalk.dim(` Generated ${storyResult.stories.length} stories for ${featureId}`));
|
|
175
|
+
const storyDir = path.join(projectDir, getArtifactDir(config, 'story'));
|
|
176
|
+
const storyIds = [];
|
|
177
|
+
const featureFilename = await resolveArtifactFilename(projectDir, config, 'feature', featureId);
|
|
178
|
+
for (const story of storyResult.stories) {
|
|
179
|
+
const { id, filePath } = await createArtifact(projectDir, config, 'story', 'stories/user-story.md.hbs', {
|
|
180
|
+
title: story.title,
|
|
181
|
+
featureId,
|
|
182
|
+
featureFilename,
|
|
183
|
+
role: story.role,
|
|
184
|
+
goal: story.goal,
|
|
185
|
+
benefit: story.benefit,
|
|
186
|
+
additionalNotes: story.additionalNotes || undefined,
|
|
187
|
+
});
|
|
188
|
+
// Gherkin file
|
|
189
|
+
const gherkinContent = await renderTemplate('stories/gherkin.feature.hbs', {
|
|
190
|
+
id,
|
|
191
|
+
title: story.title,
|
|
192
|
+
role: story.role,
|
|
193
|
+
goal: story.goal,
|
|
194
|
+
benefit: story.benefit,
|
|
195
|
+
scenarios: story.gherkinScenarios.map((s) => ({
|
|
196
|
+
name: s.name, given: s.given, when: s.when, then: s.then,
|
|
197
|
+
})),
|
|
198
|
+
}, config.templateOverrides);
|
|
199
|
+
await writeFile(path.join(storyDir, `${id}-gherkin.feature`), gherkinContent);
|
|
200
|
+
storyIds.push(id);
|
|
201
|
+
await addChildReference(projectDir, config, 'feature', featureId, 'story', id, story.title);
|
|
202
|
+
logger.success(`Created ${id}: ${story.title}`);
|
|
203
|
+
}
|
|
204
|
+
// Step 4: Generate tasks for each story
|
|
205
|
+
for (const storyId of storyIds) {
|
|
206
|
+
await generateTasksForStory(projectDir, config, provider, storyId);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async function generateTasksForStory(projectDir, config, provider, storyId) {
|
|
210
|
+
const { gatherStoryArtifacts } = await import('../../services/artifact-gathering.js');
|
|
211
|
+
let ctx;
|
|
212
|
+
try {
|
|
213
|
+
ctx = await gatherStoryArtifacts(projectDir, config, storyId);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
logger.error(`Story ${storyId} not found.`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
logger.dim(`\n[4/4] Generating tasks for ${storyId}...`);
|
|
220
|
+
ctx.scope = { type: 'story', id: storyId };
|
|
221
|
+
const taskMessages = buildTasksPrompt(ctx);
|
|
222
|
+
const result = await generateStreamingJSON(provider, taskMessages, aiTasksResponseSchema);
|
|
223
|
+
const tasks = result.tasks.map((tg) => ({
|
|
224
|
+
id: tg.id,
|
|
225
|
+
title: tg.title,
|
|
226
|
+
status: 'pending',
|
|
227
|
+
subtasks: (tg.subtasks || []).map((st) => ({
|
|
228
|
+
id: st.id,
|
|
229
|
+
title: st.title,
|
|
230
|
+
status: 'pending',
|
|
231
|
+
subtasks: [],
|
|
232
|
+
})),
|
|
233
|
+
}));
|
|
234
|
+
const storyFilename = await resolveArtifactFilename(projectDir, config, 'story', storyId);
|
|
235
|
+
// Build artifact sources for traceability
|
|
236
|
+
const artifactSources = [];
|
|
237
|
+
for (const s of ctx.stories) {
|
|
238
|
+
artifactSources.push({ type: 'User Story', path: `${config.outputPaths.agile}/stories/${s.id}` });
|
|
239
|
+
}
|
|
240
|
+
for (const g of ctx.gherkinScenarios) {
|
|
241
|
+
artifactSources.push({ type: 'Gherkin', path: `${config.outputPaths.agile}/stories/${g.storyId}-gherkin.feature` });
|
|
242
|
+
}
|
|
243
|
+
for (const a of ctx.adrs) {
|
|
244
|
+
artifactSources.push({ type: 'ADR', path: `${config.outputPaths.agile}/adrs/${a.id}` });
|
|
245
|
+
}
|
|
246
|
+
const { id } = await createArtifact(projectDir, config, 'task', 'tasks/task-list.md.hbs', {
|
|
247
|
+
title: result.title,
|
|
248
|
+
storyId,
|
|
249
|
+
storyFilename,
|
|
250
|
+
tasks,
|
|
251
|
+
artifactSources,
|
|
252
|
+
acceptanceCriteriaMapping: result.acceptanceCriteriaMapping,
|
|
253
|
+
relevantFiles: result.relevantFiles,
|
|
254
|
+
});
|
|
255
|
+
const total = tasks.reduce((sum, t) => sum + t.subtasks.length + 1, 0);
|
|
256
|
+
await addChildReference(projectDir, config, 'story', storyId, 'task', id, result.title);
|
|
257
|
+
logger.success(`Created ${id}: ${result.title} (${total} tasks)`);
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=plan.js.map
|