openplanr 0.1.0 → 0.3.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 +23 -5
- 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 +124 -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 +425 -0
- package/dist/ai/schemas/ai-response-schemas.d.ts.map +1 -0
- package/dist/ai/schemas/ai-response-schemas.js +87 -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/checklist.d.ts.map +1 -1
- package/dist/cli/commands/checklist.js +60 -1
- package/dist/cli/commands/checklist.js.map +1 -1
- 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 +101 -0
- package/dist/cli/commands/refine.js.map +1 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +150 -18
- package/dist/cli/commands/status.js.map +1 -1
- 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 +259 -45
- 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 +227 -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 +350 -35
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/index.js +16 -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 +169 -0
- package/dist/services/artifact-service.js.map +1 -1
- package/dist/services/checklist-service.d.ts +23 -0
- package/dist/services/checklist-service.d.ts.map +1 -1
- package/dist/services/checklist-service.js +44 -0
- package/dist/services/checklist-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 +6 -0
- package/dist/services/prompt-service.d.ts.map +1 -1
- package/dist/services/prompt-service.js +7 -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 +6 -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/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +12 -0
- package/dist/utils/logger.js.map +1 -1
- package/package.json +12 -5
- 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
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr config` command group.
|
|
3
|
+
*
|
|
4
|
+
* Manage AI provider settings, API keys, and coding agent preferences.
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
export declare function registerConfigCommand(program: Command): void;
|
|
8
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,QAoHrD"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr config` command group.
|
|
3
|
+
*
|
|
4
|
+
* Manage AI provider settings, API keys, and coding agent preferences.
|
|
5
|
+
*/
|
|
6
|
+
import { loadConfig, saveConfig } from '../../services/config-service.js';
|
|
7
|
+
import { saveCredential, resolveApiKey } from '../../services/credentials-service.js';
|
|
8
|
+
import { promptSelect, promptSecret } from '../../services/prompt-service.js';
|
|
9
|
+
import { logger } from '../../utils/logger.js';
|
|
10
|
+
export function registerConfigCommand(program) {
|
|
11
|
+
const config = program.command('config').description('Manage Planr configuration');
|
|
12
|
+
config
|
|
13
|
+
.command('show')
|
|
14
|
+
.description('Display current configuration')
|
|
15
|
+
.action(async () => {
|
|
16
|
+
const projectDir = program.opts().projectDir;
|
|
17
|
+
const cfg = await loadConfig(projectDir);
|
|
18
|
+
logger.heading('Planr Configuration');
|
|
19
|
+
console.log(` Project: ${cfg.projectName}`);
|
|
20
|
+
console.log(` Targets: ${cfg.targets.join(', ')}`);
|
|
21
|
+
console.log(` Artifacts: ${cfg.outputPaths.agile}/`);
|
|
22
|
+
if (cfg.ai) {
|
|
23
|
+
console.log('');
|
|
24
|
+
console.log(` AI Provider: ${cfg.ai.provider}`);
|
|
25
|
+
console.log(` AI Model: ${cfg.ai.model || '(default)'}`);
|
|
26
|
+
const key = await resolveApiKey(cfg.ai.provider);
|
|
27
|
+
if (key) {
|
|
28
|
+
const masked = key.slice(0, 8) + '...' + key.slice(-4);
|
|
29
|
+
console.log(` API Key: ${masked}`);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.log(` API Key: (not set)`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.log('');
|
|
37
|
+
console.log(' AI: Not configured');
|
|
38
|
+
logger.dim(' Run `planr config set-provider <name>` to enable AI.');
|
|
39
|
+
}
|
|
40
|
+
if (cfg.defaultAgent) {
|
|
41
|
+
console.log(` Agent: ${cfg.defaultAgent}`);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
config
|
|
45
|
+
.command('set-provider')
|
|
46
|
+
.description('Set the AI provider')
|
|
47
|
+
.argument('[provider]', 'anthropic, openai, or ollama')
|
|
48
|
+
.action(async (provider) => {
|
|
49
|
+
const projectDir = program.opts().projectDir;
|
|
50
|
+
const cfg = await loadConfig(projectDir);
|
|
51
|
+
const selected = provider ||
|
|
52
|
+
(await promptSelect('AI provider:', [
|
|
53
|
+
{ name: 'Anthropic (Claude)', value: 'anthropic' },
|
|
54
|
+
{ name: 'OpenAI (GPT-4o)', value: 'openai' },
|
|
55
|
+
{ name: 'Ollama (Local)', value: 'ollama' },
|
|
56
|
+
]));
|
|
57
|
+
cfg.ai = { ...cfg.ai, provider: selected };
|
|
58
|
+
await saveConfig(projectDir, cfg);
|
|
59
|
+
logger.success(`AI provider set to: ${selected}`);
|
|
60
|
+
});
|
|
61
|
+
config
|
|
62
|
+
.command('set-key')
|
|
63
|
+
.description('Store an API key securely')
|
|
64
|
+
.argument('[provider]', 'anthropic or openai')
|
|
65
|
+
.action(async (provider) => {
|
|
66
|
+
const selected = provider ||
|
|
67
|
+
(await promptSelect('Provider:', [
|
|
68
|
+
{ name: 'Anthropic', value: 'anthropic' },
|
|
69
|
+
{ name: 'OpenAI', value: 'openai' },
|
|
70
|
+
]));
|
|
71
|
+
const key = await promptSecret(`API key for ${selected}:`);
|
|
72
|
+
if (!key.trim()) {
|
|
73
|
+
logger.error('API key cannot be empty.');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
await saveCredential(selected, key.trim());
|
|
77
|
+
logger.success(`API key for ${selected} saved to ~/.planr/credentials.json`);
|
|
78
|
+
});
|
|
79
|
+
config
|
|
80
|
+
.command('set-model')
|
|
81
|
+
.description('Set the AI model')
|
|
82
|
+
.argument('<model>', 'model name (e.g., claude-sonnet-4-20250514, gpt-4o, llama3.1)')
|
|
83
|
+
.action(async (model) => {
|
|
84
|
+
const projectDir = program.opts().projectDir;
|
|
85
|
+
const cfg = await loadConfig(projectDir);
|
|
86
|
+
if (!cfg.ai) {
|
|
87
|
+
logger.error('AI not configured. Run `planr config set-provider` first.');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
cfg.ai.model = model;
|
|
91
|
+
await saveConfig(projectDir, cfg);
|
|
92
|
+
logger.success(`AI model set to: ${model}`);
|
|
93
|
+
});
|
|
94
|
+
config
|
|
95
|
+
.command('set-agent')
|
|
96
|
+
.description('Set the default coding agent for task implementation')
|
|
97
|
+
.argument('[agent]', 'claude, cursor, or codex')
|
|
98
|
+
.action(async (agent) => {
|
|
99
|
+
const projectDir = program.opts().projectDir;
|
|
100
|
+
const cfg = await loadConfig(projectDir);
|
|
101
|
+
const selected = agent ||
|
|
102
|
+
(await promptSelect('Default coding agent:', [
|
|
103
|
+
{ name: 'Claude Code CLI', value: 'claude' },
|
|
104
|
+
{ name: 'Cursor', value: 'cursor' },
|
|
105
|
+
{ name: 'Codex', value: 'codex' },
|
|
106
|
+
]));
|
|
107
|
+
cfg.defaultAgent = selected;
|
|
108
|
+
await saveConfig(projectDir, cfg);
|
|
109
|
+
logger.success(`Default coding agent set to: ${selected}`);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr epic` command group.
|
|
3
|
+
*
|
|
4
|
+
* AI-powered by default: user provides a brief description,
|
|
5
|
+
* AI expands into a full epic. Use --manual for the legacy
|
|
6
|
+
* interactive prompt flow.
|
|
7
|
+
*/
|
|
1
8
|
import { Command } from 'commander';
|
|
2
9
|
export declare function registerEpicCommand(program: Command): void;
|
|
3
10
|
//# sourceMappingURL=epic.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"epic.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/epic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"epic.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/epic.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,QA0CnD"}
|
|
@@ -1,7 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr epic` command group.
|
|
3
|
+
*
|
|
4
|
+
* AI-powered by default: user provides a brief description,
|
|
5
|
+
* AI expands into a full epic. Use --manual for the legacy
|
|
6
|
+
* interactive prompt flow.
|
|
7
|
+
*/
|
|
1
8
|
import { loadConfig } from '../../services/config-service.js';
|
|
2
9
|
import { createArtifact, listArtifacts } from '../../services/artifact-service.js';
|
|
3
|
-
import {
|
|
10
|
+
import { isAIConfigured, getAIProvider, generateStreamingJSON } from '../../services/ai-service.js';
|
|
11
|
+
import { promptText, promptMultiText, promptSelect, promptEditor } from '../../services/prompt-service.js';
|
|
12
|
+
import { buildEpicPrompt } from '../../ai/prompts/prompt-builder.js';
|
|
13
|
+
import { aiEpicResponseSchema } from '../../ai/schemas/ai-response-schemas.js';
|
|
4
14
|
import { logger } from '../../utils/logger.js';
|
|
15
|
+
import chalk from 'chalk';
|
|
5
16
|
export function registerEpicCommand(program) {
|
|
6
17
|
const epic = program.command('epic').description('Manage epics');
|
|
7
18
|
epic
|
|
@@ -9,37 +20,20 @@ export function registerEpicCommand(program) {
|
|
|
9
20
|
.description('Create a new epic')
|
|
10
21
|
.option('--title <title>', 'epic title')
|
|
11
22
|
.option('--owner <owner>', 'epic owner')
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const risks = await promptText('Risks:', 'None');
|
|
26
|
-
const { id, filePath } = await createArtifact(projectDir, config, 'epic', 'epics/epic.md.hbs', {
|
|
27
|
-
title,
|
|
28
|
-
owner,
|
|
29
|
-
businessValue,
|
|
30
|
-
targetUsers,
|
|
31
|
-
problemStatement,
|
|
32
|
-
solutionOverview,
|
|
33
|
-
successCriteria,
|
|
34
|
-
keyFeatures,
|
|
35
|
-
dependencies,
|
|
36
|
-
risks,
|
|
37
|
-
featureIds: [],
|
|
38
|
-
});
|
|
39
|
-
logger.success(`Created epic ${id}: ${title}`);
|
|
40
|
-
logger.dim(` ${filePath}`);
|
|
41
|
-
logger.dim('');
|
|
42
|
-
logger.dim(`Next: planr feature create --epic ${id}`);
|
|
27
|
+
const useAI = !opts.manual && isAIConfigured(config);
|
|
28
|
+
if (useAI) {
|
|
29
|
+
await createEpicWithAI(projectDir, config, opts);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
if (!opts.manual && !isAIConfigured(config)) {
|
|
33
|
+
logger.warn('AI not configured. Using manual mode. Run `planr config set-provider` to enable AI.');
|
|
34
|
+
}
|
|
35
|
+
await createEpicManually(projectDir, config, opts);
|
|
36
|
+
}
|
|
43
37
|
});
|
|
44
38
|
epic
|
|
45
39
|
.command('list')
|
|
@@ -53,9 +47,145 @@ export function registerEpicCommand(program) {
|
|
|
53
47
|
return;
|
|
54
48
|
}
|
|
55
49
|
logger.heading('Epics');
|
|
56
|
-
for (const
|
|
57
|
-
console.log(` ${
|
|
50
|
+
for (const e of epics) {
|
|
51
|
+
console.log(` ${e.id} ${e.title}`);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function displayEpic(epicData) {
|
|
56
|
+
console.log(chalk.dim('━'.repeat(50)));
|
|
57
|
+
console.log(chalk.bold(` Title: ${epicData.title}`));
|
|
58
|
+
console.log(` Owner: ${epicData.owner}`);
|
|
59
|
+
console.log(` Business Value: ${epicData.businessValue}`);
|
|
60
|
+
console.log(` Target Users: ${epicData.targetUsers}`);
|
|
61
|
+
console.log(` Problem: ${epicData.problemStatement}`);
|
|
62
|
+
console.log(` Solution: ${epicData.solutionOverview}`);
|
|
63
|
+
console.log(` Success Criteria:`);
|
|
64
|
+
const criteria = Array.isArray(epicData.successCriteria) ? epicData.successCriteria : [epicData.successCriteria];
|
|
65
|
+
for (const c of criteria) {
|
|
66
|
+
console.log(` • ${c}`);
|
|
67
|
+
}
|
|
68
|
+
console.log(` Key Features:`);
|
|
69
|
+
for (const f of epicData.keyFeatures) {
|
|
70
|
+
console.log(` • ${f}`);
|
|
71
|
+
}
|
|
72
|
+
console.log(` Dependencies: ${epicData.dependencies || 'None'}`);
|
|
73
|
+
console.log(` Risks: ${epicData.risks || 'None'}`);
|
|
74
|
+
console.log(chalk.dim('━'.repeat(50)));
|
|
75
|
+
}
|
|
76
|
+
async function createEpicWithAI(projectDir, config, opts) {
|
|
77
|
+
logger.heading('Create Epic (AI-powered)');
|
|
78
|
+
const brief = opts.title || await promptText('Describe your epic in a sentence or two:');
|
|
79
|
+
// Get existing epics for deduplication
|
|
80
|
+
const existingEpics = await listArtifacts(projectDir, config, 'epic');
|
|
81
|
+
const existingTitles = existingEpics.map((e) => `${e.id}: ${e.title}`);
|
|
82
|
+
logger.dim('AI is generating your epic...');
|
|
83
|
+
try {
|
|
84
|
+
const provider = await getAIProvider(config);
|
|
85
|
+
const messages = buildEpicPrompt(brief, existingTitles);
|
|
86
|
+
let epicData = await generateStreamingJSON(provider, messages, aiEpicResponseSchema);
|
|
87
|
+
displayEpic(epicData);
|
|
88
|
+
// Action loop: save, edit, regenerate, cancel
|
|
89
|
+
let saved = false;
|
|
90
|
+
while (!saved) {
|
|
91
|
+
const action = await promptSelect('Action:', [
|
|
92
|
+
{ name: 'Save this epic', value: 'save' },
|
|
93
|
+
{ name: 'Edit before saving', value: 'edit' },
|
|
94
|
+
{ name: 'Regenerate', value: 'regenerate' },
|
|
95
|
+
{ name: 'Cancel', value: 'cancel' },
|
|
96
|
+
]);
|
|
97
|
+
if (action === 'cancel') {
|
|
98
|
+
logger.info('Epic creation cancelled.');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (action === 'regenerate') {
|
|
102
|
+
logger.dim('Regenerating...');
|
|
103
|
+
epicData = await generateStreamingJSON(provider, messages, aiEpicResponseSchema);
|
|
104
|
+
displayEpic(epicData);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (action === 'edit') {
|
|
108
|
+
const editContent = JSON.stringify(epicData, null, 2);
|
|
109
|
+
const edited = await promptEditor('Edit the epic JSON (save & close to apply):', editContent);
|
|
110
|
+
try {
|
|
111
|
+
const parsed = JSON.parse(edited);
|
|
112
|
+
const validated = aiEpicResponseSchema.parse(parsed);
|
|
113
|
+
epicData = validated;
|
|
114
|
+
displayEpic(epicData);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
logger.error('Invalid JSON after edit. Please try again.');
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Save
|
|
123
|
+
saved = true;
|
|
124
|
+
}
|
|
125
|
+
const criteriaArray = Array.isArray(epicData.successCriteria)
|
|
126
|
+
? epicData.successCriteria
|
|
127
|
+
: [epicData.successCriteria];
|
|
128
|
+
const templateData = {
|
|
129
|
+
...epicData,
|
|
130
|
+
successCriteria: criteriaArray.join('; '),
|
|
131
|
+
successCriteriaList: criteriaArray,
|
|
132
|
+
featureIds: [],
|
|
133
|
+
};
|
|
134
|
+
const { id, filePath } = await createArtifact(projectDir, config, 'epic', 'epics/epic.md.hbs', templateData);
|
|
135
|
+
logger.success(`Created epic ${id}: ${epicData.title}`);
|
|
136
|
+
logger.dim(` ${filePath}`);
|
|
137
|
+
logger.dim('');
|
|
138
|
+
logger.heading('Next steps:');
|
|
139
|
+
logger.dim(` 1. planr feature create --epic ${id} — Break epic into features`);
|
|
140
|
+
logger.dim(` 2. planr story create --feature FEAT-* — Create user stories per feature`);
|
|
141
|
+
logger.dim(` 3. planr task create --story US-* — Generate implementation tasks`);
|
|
142
|
+
logger.dim(` 4. planr task implement TASK-* — Implement with your coding agent`);
|
|
143
|
+
logger.dim('');
|
|
144
|
+
logger.dim(` Or run the full flow at once:`);
|
|
145
|
+
logger.dim(` planr plan --epic ${id} — Auto-generate features → stories → tasks`);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
const { AIError } = await import('../../ai/errors.js');
|
|
149
|
+
if (err instanceof AIError) {
|
|
150
|
+
logger.error(err.userMessage);
|
|
58
151
|
}
|
|
152
|
+
else {
|
|
153
|
+
throw err;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function createEpicManually(projectDir, config, opts) {
|
|
158
|
+
logger.heading('Create Epic');
|
|
159
|
+
const title = opts.title || (await promptText('Epic title:'));
|
|
160
|
+
const owner = opts.owner || (await promptText('Owner:', config.author));
|
|
161
|
+
const businessValue = await promptText('Business value:');
|
|
162
|
+
const targetUsers = await promptText('Target users:');
|
|
163
|
+
const problemStatement = await promptText('Problem statement:');
|
|
164
|
+
const solutionOverview = await promptText('Solution overview:');
|
|
165
|
+
const successCriteria = await promptText('Success criteria:');
|
|
166
|
+
const keyFeatures = await promptMultiText('Key features', 'comma-separated');
|
|
167
|
+
const dependencies = await promptText('Dependencies:', 'None');
|
|
168
|
+
const risks = await promptText('Risks:', 'None');
|
|
169
|
+
const { id, filePath } = await createArtifact(projectDir, config, 'epic', 'epics/epic.md.hbs', {
|
|
170
|
+
title,
|
|
171
|
+
owner,
|
|
172
|
+
businessValue,
|
|
173
|
+
targetUsers,
|
|
174
|
+
problemStatement,
|
|
175
|
+
solutionOverview,
|
|
176
|
+
successCriteria,
|
|
177
|
+
keyFeatures,
|
|
178
|
+
dependencies,
|
|
179
|
+
risks,
|
|
180
|
+
featureIds: [],
|
|
59
181
|
});
|
|
182
|
+
logger.success(`Created epic ${id}: ${title}`);
|
|
183
|
+
logger.dim(` ${filePath}`);
|
|
184
|
+
logger.dim('');
|
|
185
|
+
logger.heading('Next steps:');
|
|
186
|
+
logger.dim(` 1. planr feature create --epic ${id} — Break epic into features`);
|
|
187
|
+
logger.dim(` 2. planr story create --feature FEAT-* — Create user stories per feature`);
|
|
188
|
+
logger.dim(` 3. planr task create --story US-* — Generate implementation tasks`);
|
|
189
|
+
logger.dim(` 4. planr task implement TASK-* — Implement with your coding agent`);
|
|
60
190
|
}
|
|
61
191
|
//# sourceMappingURL=epic.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"epic.js","sourceRoot":"","sources":["../../../src/cli/commands/epic.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"epic.js","sourceRoot":"","sources":["../../../src/cli/commands/epic.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,9 @@
|
|
|
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 { Command } from 'commander';
|
|
2
8
|
export declare function registerFeatureCommand(program: Command): void;
|
|
3
9
|
//# sourceMappingURL=feature.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/feature.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/feature.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,QAmDtD"}
|
|
@@ -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
|