@krr2020/taskflow-core 0.1.0-beta.3 → 0.1.0-beta.5

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.
Files changed (62) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/index.js +42 -4
  3. package/dist/commands/base.d.ts +41 -0
  4. package/dist/commands/base.js +141 -0
  5. package/dist/commands/configure.d.ts +29 -0
  6. package/dist/commands/configure.js +187 -0
  7. package/dist/commands/init.js +21 -7
  8. package/dist/commands/prd/create.d.ts +1 -1
  9. package/dist/commands/prd/create.js +29 -11
  10. package/dist/commands/prd/generate-arch.d.ts +1 -1
  11. package/dist/commands/prd/generate-arch.js +6 -5
  12. package/dist/commands/retro/list.js +6 -5
  13. package/dist/commands/tasks/generate.d.ts +1 -1
  14. package/dist/commands/tasks/generate.js +83 -56
  15. package/dist/commands/upgrade.js +49 -16
  16. package/dist/commands/workflow/check.d.ts +17 -0
  17. package/dist/commands/workflow/check.js +482 -35
  18. package/dist/commands/workflow/commit.js +117 -60
  19. package/dist/commands/workflow/do.d.ts +1 -0
  20. package/dist/commands/workflow/do.js +206 -13
  21. package/dist/commands/workflow/next.js +4 -4
  22. package/dist/commands/workflow/resume.js +9 -6
  23. package/dist/commands/workflow/start.js +11 -11
  24. package/dist/index.d.ts +4 -0
  25. package/dist/index.js +6 -0
  26. package/dist/lib/config-paths.d.ts +15 -15
  27. package/dist/lib/config-paths.js +20 -15
  28. package/dist/lib/file-validator.d.ts +119 -0
  29. package/dist/lib/file-validator.js +291 -0
  30. package/dist/lib/git.js +4 -2
  31. package/dist/lib/log-parser.d.ts +91 -0
  32. package/dist/lib/log-parser.js +178 -0
  33. package/dist/lib/retrospective.d.ts +27 -0
  34. package/dist/lib/retrospective.js +111 -1
  35. package/dist/lib/types.d.ts +19 -6
  36. package/dist/lib/types.js +20 -1
  37. package/dist/lib/validation.d.ts +0 -3
  38. package/dist/lib/validation.js +1 -15
  39. package/dist/llm/base.d.ts +52 -0
  40. package/dist/llm/base.js +35 -0
  41. package/dist/llm/factory.d.ts +39 -0
  42. package/dist/llm/factory.js +102 -0
  43. package/dist/llm/index.d.ts +7 -0
  44. package/dist/llm/index.js +7 -0
  45. package/dist/llm/model-selector.d.ts +71 -0
  46. package/dist/llm/model-selector.js +139 -0
  47. package/dist/llm/providers/anthropic.d.ts +31 -0
  48. package/dist/llm/providers/anthropic.js +116 -0
  49. package/dist/llm/providers/index.d.ts +6 -0
  50. package/dist/llm/providers/index.js +6 -0
  51. package/dist/llm/providers/ollama.d.ts +28 -0
  52. package/dist/llm/providers/ollama.js +91 -0
  53. package/dist/llm/providers/openai-compatible.d.ts +30 -0
  54. package/dist/llm/providers/openai-compatible.js +93 -0
  55. package/dist/schemas/config.d.ts +82 -0
  56. package/dist/schemas/config.js +35 -0
  57. package/dist/schemas/task.d.ts +2 -2
  58. package/dist/state-machine.d.ts +12 -0
  59. package/dist/state-machine.js +2 -2
  60. package/package.json +1 -1
  61. package/dist/lib/package-manager.d.ts +0 -17
  62. package/dist/lib/package-manager.js +0 -53
package/README.md CHANGED
@@ -172,7 +172,7 @@ Most users should use this package via:
172
172
  - **[@krr2020/taskflow-mcp-server](https://www.npmjs.com/package/@krr2020/taskflow-mcp-server)** - MCP Server for Claude Desktop
173
173
  - **CLI** - Direct command-line usage via `npx @krr2020/taskflow-core`
174
174
 
175
- See the main [Taskflow documentation](../../README.md) for complete usage examples.
175
+ See the main [Taskflow documentation](../README.md) for complete usage examples.
176
176
 
177
177
  ## 📄 License
178
178
 
package/dist/cli/index.js CHANGED
@@ -4,6 +4,7 @@
4
4
  import process from "node:process";
5
5
  import { Command } from "commander";
6
6
  // Import commands
7
+ import { ConfigureAICommand } from "../commands/configure.js";
7
8
  import { InitCommand } from "../commands/init.js";
8
9
  import { PrdCreateCommand } from "../commands/prd/create.js";
9
10
  import { PrdGenerateArchCommand } from "../commands/prd/generate-arch.js";
@@ -51,6 +52,42 @@ export async function runCLI() {
51
52
  }
52
53
  });
53
54
  // ========================================
55
+ // CONFIGURE COMMAND
56
+ // ========================================
57
+ const configureCommand = program
58
+ .command("configure")
59
+ .description("Configure taskflow settings");
60
+ configureCommand
61
+ .command("ai")
62
+ .description("Configure AI/LLM provider for manual command execution")
63
+ .option("--provider <provider>", "Provider type (openai-compatible, anthropic, ollama)")
64
+ .option("--apiKey <key>", "API key for the provider (can use $${ENV_VAR} format)")
65
+ .option("--model <model>", "Default model to use")
66
+ .option("--planning <model>", "Model for planning phase (e.g., claude-opus-4)")
67
+ .option("--execution <model>", "Model for execution phase (e.g., gemini-pro-2.0)")
68
+ .option("--analysis <model>", "Model for analysis phase (e.g., claude-sonnet-4)")
69
+ .option("--planningProvider <provider>", "Different provider for planning")
70
+ .option("--planningApiKey <key>", "API key for planning provider")
71
+ .option("--executionProvider <provider>", "Different provider for execution")
72
+ .option("--executionApiKey <key>", "API key for execution provider")
73
+ .option("--analysisProvider <provider>", "Different provider for analysis")
74
+ .option("--analysisApiKey <key>", "API key for analysis provider")
75
+ .option("--ollamaBaseUrl <url>", "Ollama base URL (default: http://localhost:11434)")
76
+ .option("--openaiBaseUrl <url>", "OpenAI-compatible base URL (default: https://api.openai.com/v1)")
77
+ .option("--enable", "Enable AI features")
78
+ .option("--disable", "Disable AI features")
79
+ .action(async (options) => {
80
+ try {
81
+ const cmd = new ConfigureAICommand(context);
82
+ const result = await cmd.execute(options);
83
+ console.log(formatSuccess(result));
84
+ process.exit(0);
85
+ }
86
+ catch (error) {
87
+ handleError(error);
88
+ }
89
+ });
90
+ // ========================================
54
91
  // UPGRADE COMMAND
55
92
  // ========================================
56
93
  program
@@ -232,10 +269,11 @@ export async function runCLI() {
232
269
  .command("create")
233
270
  .description("Create a new PRD")
234
271
  .argument("<feature-name>", "Name of the feature")
235
- .action(async (featureName) => {
272
+ .option("--description <desc>", "Feature description/requirements (optional)")
273
+ .action(async (featureName, options) => {
236
274
  try {
237
275
  const cmd = new PrdCreateCommand(context);
238
- const result = await cmd.execute(featureName);
276
+ const result = await cmd.execute(featureName, options.description);
239
277
  console.log(formatSuccess(result));
240
278
  process.exit(0);
241
279
  }
@@ -245,7 +283,7 @@ export async function runCLI() {
245
283
  });
246
284
  prdCommand
247
285
  .command("generate-arch")
248
- .description("Generate CODING-STANDARDS.md and ARCHITECTURE-RULES.md from PRD")
286
+ .description("Generate coding-standards.md and architecture-rules.md from PRD")
249
287
  .argument("<prd-file>", "PRD filename")
250
288
  .action(async (prdFile) => {
251
289
  try {
@@ -267,7 +305,7 @@ export async function runCLI() {
267
305
  tasksCommand
268
306
  .command("generate")
269
307
  .description("Generate task breakdown from PRD")
270
- .argument("<prd-file>", "PRD filename")
308
+ .argument("[prd-file]", "PRD filename (optional - shows selection if not provided)")
271
309
  .action(async (prdFile) => {
272
310
  try {
273
311
  const cmd = new TasksGenerateCommand(context);
@@ -2,6 +2,8 @@
2
2
  * Base command infrastructure for AI-first command design
3
3
  * Every command returns structured guidance for AI agents
4
4
  */
5
+ import { ConfigLoader } from "../lib/config-loader.js";
6
+ import type { LLMProvider } from "../llm/base.js";
5
7
  export interface CommandContext {
6
8
  projectRoot: string;
7
9
  }
@@ -16,7 +18,46 @@ export interface CommandResult {
16
18
  }
17
19
  export declare abstract class BaseCommand {
18
20
  protected context: CommandContext;
21
+ protected llmProvider: LLMProvider | undefined;
22
+ protected configLoader: ConfigLoader;
19
23
  constructor(context: CommandContext);
24
+ /**
25
+ * Initialize LLM provider if configured
26
+ */
27
+ private initializeLLMProvider;
28
+ /**
29
+ * Check if LLM is available
30
+ */
31
+ protected isLLMAvailable(): boolean;
32
+ /**
33
+ * Get LLM guidance for a given context
34
+ * Keeps guidance concise (200 words max)
35
+ */
36
+ protected getLLMGuidance(context: {
37
+ task?: string;
38
+ status?: string;
39
+ files?: string[];
40
+ errors?: string[];
41
+ instructions?: string;
42
+ }): Promise<string>;
43
+ /**
44
+ * Get error analysis with LLM
45
+ * Groups errors by file and provides targeted fixes
46
+ */
47
+ protected getErrorAnalysis(errors: Array<{
48
+ file: string;
49
+ message: string;
50
+ line?: number;
51
+ code?: string;
52
+ }>): Promise<string>;
53
+ /**
54
+ * Group errors by file
55
+ */
56
+ private groupErrorsByFile;
57
+ /**
58
+ * Truncate text to maximum word count
59
+ */
60
+ private truncateToWords;
20
61
  abstract execute(...args: unknown[]): Promise<CommandResult>;
21
62
  /**
22
63
  * Format command result for terminal output
@@ -2,10 +2,151 @@
2
2
  * Base command infrastructure for AI-first command design
3
3
  * Every command returns structured guidance for AI agents
4
4
  */
5
+ import { ConfigLoader } from "../lib/config-loader.js";
6
+ import { Phase } from "../llm/base.js";
7
+ import { ProviderFactory } from "../llm/factory.js";
5
8
  export class BaseCommand {
6
9
  context;
10
+ llmProvider;
11
+ configLoader;
7
12
  constructor(context) {
8
13
  this.context = context;
14
+ this.configLoader = new ConfigLoader(context.projectRoot);
15
+ this.initializeLLMProvider();
16
+ }
17
+ /**
18
+ * Initialize LLM provider if configured
19
+ */
20
+ initializeLLMProvider() {
21
+ try {
22
+ const config = this.configLoader.load();
23
+ // Check if AI is configured and enabled
24
+ if (config.ai && "enabled" in config.ai && config.ai.enabled) {
25
+ const aiConfig = config.ai;
26
+ const selector = ProviderFactory.createSelector(aiConfig);
27
+ if (selector.isConfigured()) {
28
+ this.llmProvider = selector.getProvider(Phase.Planning);
29
+ }
30
+ }
31
+ }
32
+ catch {
33
+ // LLM provider initialization failed gracefully
34
+ this.llmProvider = void 0;
35
+ }
36
+ }
37
+ /**
38
+ * Check if LLM is available
39
+ */
40
+ isLLMAvailable() {
41
+ return this.llmProvider?.isConfigured() === true;
42
+ }
43
+ /**
44
+ * Get LLM guidance for a given context
45
+ * Keeps guidance concise (200 words max)
46
+ */
47
+ async getLLMGuidance(context) {
48
+ if (!this.isLLMAvailable() || !this.llmProvider) {
49
+ return "";
50
+ }
51
+ try {
52
+ const { task, status, files, errors, instructions } = context;
53
+ const prompt = `Generate concise guidance (max 200 words) for:
54
+ ${task ? `Task: ${task}` : ""}
55
+ ${status ? `Status: ${status}` : ""}
56
+ ${files && files.length > 0 ? `Files: ${files.slice(0, 5).join(", ")}` : ""}
57
+ ${errors && errors.length > 0 ? `Errors: ${errors.slice(0, 3).join("; ")}` : ""}
58
+ ${instructions ? `Instructions: ${instructions}` : ""}
59
+
60
+ Provide:
61
+ 1. Key context to understand
62
+ 2. Critical files to check
63
+ 3. Common pitfalls to avoid
64
+ 4. Recommended approach
65
+
66
+ Be concise and actionable.`;
67
+ const response = await this.llmProvider.generate([
68
+ {
69
+ role: "system",
70
+ content: "You are a helpful coding assistant providing concise guidance.",
71
+ },
72
+ { role: "user", content: prompt },
73
+ ], { maxTokens: 300, temperature: 0.5 });
74
+ return this.truncateToWords(response.content, 200);
75
+ }
76
+ catch {
77
+ // LLM call failed, return empty string
78
+ return "";
79
+ }
80
+ }
81
+ /**
82
+ * Get error analysis with LLM
83
+ * Groups errors by file and provides targeted fixes
84
+ */
85
+ async getErrorAnalysis(errors) {
86
+ if (!this.isLLMAvailable() || !this.llmProvider || errors.length === 0) {
87
+ return "";
88
+ }
89
+ try {
90
+ const groupedErrors = this.groupErrorsByFile(errors);
91
+ const prompt = `Analyze these errors and provide targeted fixes:
92
+
93
+ ${Object.entries(groupedErrors)
94
+ .map(([file, fileErrors]) => `\n${file}:\n${fileErrors.map((e) => ` ${e.message}`).join("\n")}`)
95
+ .join("\n")}
96
+
97
+ Provide:
98
+ 1. Root cause analysis per file
99
+ 2. Specific fix suggestions
100
+ 3. File-by-file approach to resolve
101
+
102
+ Be concise and actionable.`;
103
+ const response = await this.llmProvider.generate([
104
+ {
105
+ role: "system",
106
+ content: "You are a debugging assistant providing error analysis.",
107
+ },
108
+ { role: "user", content: prompt },
109
+ ], { maxTokens: 500, temperature: 0.3 });
110
+ return response.content;
111
+ }
112
+ catch {
113
+ return "";
114
+ }
115
+ }
116
+ /**
117
+ * Group errors by file
118
+ */
119
+ groupErrorsByFile(errors) {
120
+ const grouped = {};
121
+ for (const error of errors) {
122
+ if (!grouped[error.file]) {
123
+ grouped[error.file] = [];
124
+ }
125
+ const entry = {
126
+ message: error.message,
127
+ };
128
+ if (error.line !== undefined) {
129
+ entry.line = error.line;
130
+ }
131
+ if (error.code !== undefined) {
132
+ entry.code = error.code;
133
+ }
134
+ const array = grouped[error.file];
135
+ if (array) {
136
+ array.push(entry);
137
+ }
138
+ }
139
+ return grouped;
140
+ }
141
+ /**
142
+ * Truncate text to maximum word count
143
+ */
144
+ truncateToWords(text, maxWords) {
145
+ const words = text.split(/\s+/);
146
+ if (words.length <= maxWords) {
147
+ return text;
148
+ }
149
+ return words.slice(0, maxWords).join(" ");
9
150
  }
10
151
  /**
11
152
  * Format command result for terminal output
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Configure AI command
3
+ * Configure LLM provider and per-phase model selection
4
+ */
5
+ import { BaseCommand, type CommandResult } from "./base.js";
6
+ export declare class ConfigureAICommand extends BaseCommand {
7
+ execute(options: {
8
+ provider?: string;
9
+ apiKey?: string;
10
+ model?: string;
11
+ planning?: string;
12
+ execution?: string;
13
+ analysis?: string;
14
+ planningProvider?: string;
15
+ planningApiKey?: string;
16
+ executionProvider?: string;
17
+ executionApiKey?: string;
18
+ analysisProvider?: string;
19
+ analysisApiKey?: string;
20
+ ollamaBaseUrl?: string;
21
+ openaiBaseUrl?: string;
22
+ enable?: boolean;
23
+ disable?: boolean;
24
+ }): Promise<CommandResult>;
25
+ private saveConfig;
26
+ private formatConfigOutput;
27
+ private generateNextSteps;
28
+ private getWarnings;
29
+ }
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Configure AI command
3
+ * Configure LLM provider and per-phase model selection
4
+ */
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import { ProviderFactory } from "../llm/factory.js";
8
+ import { BaseCommand } from "./base.js";
9
+ export class ConfigureAICommand extends BaseCommand {
10
+ async execute(options) {
11
+ const configPath = path.join(this.context.projectRoot, "taskflow.config.json");
12
+ if (!fs.existsSync(configPath)) {
13
+ return this.failure("Configuration file not found", [
14
+ `taskflow.config.json not found in ${this.context.projectRoot}`,
15
+ "Run 'taskflow init' to initialize the project first",
16
+ ], "Initialize taskflow with 'taskflow init'");
17
+ }
18
+ // Load existing config
19
+ const raw = fs.readFileSync(configPath, "utf-8");
20
+ const config = JSON.parse(raw);
21
+ // Check for enable/disable flags
22
+ if (options.disable) {
23
+ config.ai = config.ai || {};
24
+ config.ai.enabled = false;
25
+ this.saveConfig(config, configPath);
26
+ return this.success("AI configuration disabled", "AI features will not be used. Commands will show guidance only.", {
27
+ aiGuidance: "To re-enable, run: taskflow configure ai --enable\n" +
28
+ "Or configure a provider: taskflow configure ai --provider anthropic --apiKey $${ANTHROPIC_API_KEY}",
29
+ });
30
+ }
31
+ if (options.enable) {
32
+ config.ai = config.ai || { enabled: true };
33
+ config.ai.enabled = true;
34
+ this.saveConfig(config, configPath);
35
+ return this.success("AI configuration enabled", "AI features will be used when properly configured with a provider.", {
36
+ aiGuidance: "Configure a provider: taskflow configure ai --provider anthropic --apiKey $${ANTHROPIC_API_KEY}",
37
+ });
38
+ }
39
+ // Ensure ai config exists
40
+ if (!config.ai) {
41
+ config.ai = {
42
+ enabled: true,
43
+ };
44
+ }
45
+ // Update basic configuration
46
+ if (options.provider) {
47
+ config.ai.provider = options.provider;
48
+ config.ai.enabled = true;
49
+ }
50
+ if (options.apiKey) {
51
+ config.ai.apiKey = options.apiKey;
52
+ }
53
+ if (options.model) {
54
+ config.ai.models = config.ai.models || { default: "gpt-4o-mini" };
55
+ config.ai.models.default = options.model;
56
+ }
57
+ // Update per-phase models
58
+ if (options.planning || options.execution || options.analysis) {
59
+ config.ai.models = config.ai.models || { default: "gpt-4o-mini" };
60
+ const models = config.ai.models;
61
+ if (options.planning) {
62
+ models.planning = options.planning;
63
+ }
64
+ if (options.execution) {
65
+ models.execution = options.execution;
66
+ }
67
+ if (options.analysis) {
68
+ models.analysis = options.analysis;
69
+ }
70
+ }
71
+ // Update per-phase providers
72
+ if (options.planningProvider ||
73
+ options.executionProvider ||
74
+ options.analysisProvider) {
75
+ if (options.planningProvider) {
76
+ config.ai.planningProvider = options.planningProvider;
77
+ }
78
+ if (options.executionProvider) {
79
+ config.ai.executionProvider = options.executionProvider;
80
+ }
81
+ if (options.analysisProvider) {
82
+ config.ai.analysisProvider = options.analysisProvider;
83
+ }
84
+ }
85
+ // Update per-phase API keys
86
+ if (options.planningApiKey ||
87
+ options.executionApiKey ||
88
+ options.analysisApiKey) {
89
+ if (options.planningApiKey) {
90
+ config.ai.planningApiKey = options.planningApiKey;
91
+ }
92
+ if (options.executionApiKey) {
93
+ config.ai.executionApiKey = options.executionApiKey;
94
+ }
95
+ if (options.analysisApiKey) {
96
+ config.ai.analysisApiKey = options.analysisApiKey;
97
+ }
98
+ }
99
+ // Update base URLs
100
+ if (options.ollamaBaseUrl) {
101
+ config.ai.ollamaBaseUrl = options.ollamaBaseUrl;
102
+ }
103
+ if (options.openaiBaseUrl) {
104
+ config.ai.openaiBaseUrl = options.openaiBaseUrl;
105
+ }
106
+ // Save config
107
+ this.saveConfig(config, configPath);
108
+ // Generate output
109
+ const output = this.formatConfigOutput(config.ai);
110
+ const nextSteps = this.generateNextSteps(config.ai);
111
+ return this.success("AI configuration updated successfully", nextSteps, {
112
+ aiGuidance: output,
113
+ warnings: this.getWarnings(config.ai),
114
+ });
115
+ }
116
+ saveConfig(config, configPath) {
117
+ fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
118
+ }
119
+ formatConfigOutput(aiConfig) {
120
+ const lines = [];
121
+ lines.push("AI Configuration:");
122
+ lines.push("─".repeat(60));
123
+ lines.push(`Enabled: ${aiConfig.enabled ? "✓" : "✗"}`);
124
+ lines.push(`Provider: ${aiConfig.provider || "Not configured"}`);
125
+ lines.push(`API Key: ${aiConfig.apiKey ? "***configured***" : "Not configured"}`);
126
+ lines.push("");
127
+ lines.push("Models:");
128
+ const models = aiConfig.models;
129
+ lines.push(` Default: ${models?.default || "Not configured"}`);
130
+ lines.push(` Planning: ${models?.planning || "Uses default"}`);
131
+ lines.push(` Execution: ${models?.execution || "Uses default"}`);
132
+ lines.push(` Analysis: ${models?.analysis || "Uses default"}`);
133
+ lines.push("");
134
+ lines.push("Per-Phase Providers:");
135
+ lines.push(` Planning: ${aiConfig.planningProvider || "Uses default provider"}`);
136
+ lines.push(` Execution: ${aiConfig.executionProvider || "Uses default provider"}`);
137
+ lines.push(` Analysis: ${aiConfig.analysisProvider || "Uses default provider"}`);
138
+ lines.push("");
139
+ lines.push("Base URLs:");
140
+ lines.push(` Ollama: ${aiConfig.ollamaBaseUrl || "http://localhost:11434"}`);
141
+ lines.push(` OpenAI: ${aiConfig.openaiBaseUrl || "https://api.openai.com/v1"}`);
142
+ return lines.join("\n");
143
+ }
144
+ generateNextSteps(aiConfig) {
145
+ if (!aiConfig.enabled) {
146
+ return "Enable AI features: taskflow configure ai --enable";
147
+ }
148
+ if (!aiConfig.provider || !aiConfig.apiKey) {
149
+ const availableProviders = ProviderFactory.getAvailableProviders();
150
+ const examples = [];
151
+ if (availableProviders.includes("anthropic")) {
152
+ examples.push(" taskflow configure ai --provider anthropic --apiKey $${ANTHROPIC_API_KEY}");
153
+ }
154
+ if (availableProviders.includes("openai-compatible")) {
155
+ examples.push(" taskflow configure ai --provider openai-compatible --apiKey $${OPENAI_API_KEY}");
156
+ }
157
+ if (availableProviders.includes("ollama")) {
158
+ examples.push(" taskflow configure ai --provider ollama");
159
+ }
160
+ return `Configure a provider:\n${examples.join("\n")}`;
161
+ }
162
+ const models = aiConfig.models;
163
+ if (!models?.planning && !models?.execution && !models?.analysis) {
164
+ return ("Configure per-phase models (optional):\n" +
165
+ " taskflow configure ai --planning claude-opus-4 --execution gemini-pro-2.0 --analysis claude-sonnet-4-20250514");
166
+ }
167
+ return "AI is fully configured. Try running: taskflow tasks generate";
168
+ }
169
+ getWarnings(aiConfig) {
170
+ const warnings = [];
171
+ if (!aiConfig.enabled) {
172
+ warnings.push("AI is disabled. Commands will show guidance only.");
173
+ }
174
+ if (!aiConfig.provider) {
175
+ warnings.push("No provider configured. Set one with --provider option.");
176
+ }
177
+ if (aiConfig.provider &&
178
+ !aiConfig.apiKey &&
179
+ aiConfig.provider !== "ollama") {
180
+ warnings.push("API key not configured for this provider.");
181
+ }
182
+ if (aiConfig.provider === "ollama" && !aiConfig.ollamaBaseUrl) {
183
+ warnings.push("Ollama base URL not configured. Using default: http://localhost:11434");
184
+ }
185
+ return warnings;
186
+ }
187
+ }
@@ -16,7 +16,21 @@ export class InitCommand extends BaseCommand {
16
16
  configLoader.getConfigPath(),
17
17
  ], "Run 'taskflow status' to view your project state.");
18
18
  }
19
- const finalProjectName = projectName || path.basename(this.context.projectRoot);
19
+ // Try to get project name from package.json, then use provided name, then fallback to directory name
20
+ let detectedProjectName;
21
+ const packageJsonPath = path.join(this.context.projectRoot, "package.json");
22
+ if (fs.existsSync(packageJsonPath)) {
23
+ try {
24
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
25
+ detectedProjectName = packageJson.name;
26
+ }
27
+ catch (_error) {
28
+ // If package.json is invalid, continue to fallback
29
+ }
30
+ }
31
+ const finalProjectName = projectName ||
32
+ detectedProjectName ||
33
+ path.basename(this.context.projectRoot);
20
34
  // Create default configuration
21
35
  const config = ConfigLoader.createDefaultConfig(finalProjectName);
22
36
  configLoader.save(config);
@@ -120,7 +134,7 @@ export class InitCommand extends BaseCommand {
120
134
  "────────────────────",
121
135
  "A PRD (Product Requirements Document) defines what you're building.",
122
136
  "The AI will help you create it by:",
123
- "1. Reading .taskflow/ref/PRD-GENERATOR.md for guidelines",
137
+ "1. Reading .taskflow/ref/prd-generator.md for guidelines",
124
138
  "2. Gathering requirements through conversation",
125
139
  "3. Creating a structured PRD document",
126
140
  "",
@@ -128,15 +142,15 @@ export class InitCommand extends BaseCommand {
128
142
  "that you can execute step-by-step.",
129
143
  ].join("\n"),
130
144
  contextFiles: [
131
- ".taskflow/ref/AI-PROTOCOL.md - Core AI operating discipline",
132
- ".taskflow/ref/PRD-GENERATOR.md - PRD creation guidelines",
133
- ".taskflow/ref/TASK-GENERATOR.md - Task breakdown guidelines",
134
- ".taskflow/ref/RETROSPECTIVE.md - Known error patterns",
145
+ ".taskflow/ref/ai-protocol.md - Core AI operating discipline",
146
+ ".taskflow/ref/prd-generator.md - PRD creation guidelines",
147
+ ".taskflow/ref/task-generator.md - Task breakdown guidelines",
148
+ ".taskflow/ref/retrospective.md - Known error patterns",
135
149
  ],
136
150
  warnings: [
137
151
  "NEVER edit files in .taskflow/ or tasks/ directories directly",
138
152
  "ALWAYS use taskflow commands for task management",
139
- "Read AI-PROTOCOL.md before starting any task",
153
+ "Read ai-protocol.md before starting any task",
140
154
  ],
141
155
  });
142
156
  }
@@ -3,6 +3,6 @@
3
3
  */
4
4
  import { BaseCommand, type CommandResult } from "../base.js";
5
5
  export declare class PrdCreateCommand extends BaseCommand {
6
- execute(featureName: string): Promise<CommandResult>;
6
+ execute(featureName: string, description?: string): Promise<CommandResult>;
7
7
  private generatePrdTemplate;
8
8
  }
@@ -7,7 +7,7 @@ import { ConfigLoader } from "../../lib/config-loader.js";
7
7
  import { getRefFilePath, REF_FILES } from "../../lib/config-paths.js";
8
8
  import { BaseCommand } from "../base.js";
9
9
  export class PrdCreateCommand extends BaseCommand {
10
- async execute(featureName) {
10
+ async execute(featureName, description) {
11
11
  const configLoader = new ConfigLoader(this.context.projectRoot);
12
12
  const paths = configLoader.getPaths();
13
13
  // Validate feature name
@@ -44,24 +44,39 @@ export class PrdCreateCommand extends BaseCommand {
44
44
  ].join("\n"));
45
45
  }
46
46
  // Create PRD template
47
- const prdTemplate = this.generatePrdTemplate(featureName);
47
+ const prdTemplate = this.generatePrdTemplate(featureName, description);
48
48
  // Write PRD file
49
49
  fs.writeFileSync(prdFilePath, prdTemplate, "utf-8");
50
- return this.success([
50
+ const initialRequirements = description
51
+ ? [
52
+ "",
53
+ "INITIAL REQUIREMENTS PROVIDED:",
54
+ "───────────────────────────────",
55
+ description,
56
+ "",
57
+ "Use this as a starting point for the PRD.",
58
+ ]
59
+ : [];
60
+ const nextStepsBase = [
51
61
  `✓ PRD created: ${prdFilename}`,
52
62
  `✓ Location: ${prdFilePath}`,
53
63
  "",
54
64
  "NEXT:",
55
65
  "─".repeat(60),
56
66
  "1. Fill out the PRD document with feature requirements",
57
- "2. Generate coding standards and architecture rules",
58
- "3. Generate task breakdown from PRD",
59
- ].join("\n"), [
67
+ ];
68
+ if (description) {
69
+ nextStepsBase.push(" (Initial requirements already provided)");
70
+ }
71
+ nextStepsBase.push("2. Generate coding standards and architecture rules");
72
+ nextStepsBase.push("3. Generate task breakdown from PRD");
73
+ return this.success(nextStepsBase.join("\n"), [
60
74
  "1. Edit the PRD file to add feature details:",
61
75
  ` Open: ${prdFilePath}`,
76
+ ...initialRequirements,
62
77
  "",
63
78
  "2. Use AI to help fill out the PRD:",
64
- " - Read .taskflow/ref/PRD-GENERATOR.md for guidance",
79
+ " - Read .taskflow/ref/prd-generator.md for guidance",
65
80
  " - Gather requirements through conversation",
66
81
  " - Document goals, user stories, and acceptance criteria",
67
82
  "",
@@ -109,7 +124,7 @@ export class PrdCreateCommand extends BaseCommand {
109
124
  "",
110
125
  "IMPORTANT:",
111
126
  "───────────",
112
- "Do NOT create CODING-STANDARDS.md or ARCHITECTURE-RULES.md yet.",
127
+ "Do NOT create coding-standards.md or architecture-rules.md yet.",
113
128
  "Those will be generated in the next step using:",
114
129
  ` taskflow prd generate-arch ${prdFilename}`,
115
130
  "",
@@ -127,14 +142,17 @@ export class PrdCreateCommand extends BaseCommand {
127
142
  `${getRefFilePath(paths.refDir, REF_FILES.aiProtocol)} - Core AI operating discipline`,
128
143
  ],
129
144
  warnings: [
130
- "DO NOT skip the PRD-GENERATOR.md - it contains critical guidance",
145
+ "DO NOT skip the prd-generator.md - it contains critical guidance",
131
146
  "DO NOT guess at requirements - ask the user for clarification",
132
147
  "DO NOT create coding standards yet - wait for generate-arch command",
133
148
  "DO ensure PRD is complete before generating tasks",
134
149
  ],
135
150
  });
136
151
  }
137
- generatePrdTemplate(featureName) {
152
+ generatePrdTemplate(featureName, description) {
153
+ const problemStatement = description
154
+ ? description.trim()
155
+ : "<!-- What problem does this feature solve? -->";
138
156
  return `# PRD: ${featureName}
139
157
 
140
158
  **Created:** ${new Date().toISOString().split("T")[0]}
@@ -146,7 +164,7 @@ export class PrdCreateCommand extends BaseCommand {
146
164
  ## 1. Overview
147
165
 
148
166
  ### Problem Statement
149
- <!-- What problem does this feature solve? -->
167
+ ${problemStatement}
150
168
 
151
169
  ### Goals
152
170
  <!-- What are we trying to achieve? -->