task-o-matic 0.0.2 ā 0.0.4
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 +96 -40
- package/dist/commands/prd.js +4 -0
- package/dist/commands/prompt.d.ts.map +1 -1
- package/dist/commands/prompt.js +69 -61
- package/dist/commands/tasks/create.d.ts +3 -0
- package/dist/commands/tasks/create.d.ts.map +1 -0
- package/dist/commands/tasks/create.js +58 -0
- package/dist/commands/tasks/delete.d.ts +3 -0
- package/dist/commands/tasks/delete.d.ts.map +1 -0
- package/dist/commands/tasks/delete.js +40 -0
- package/dist/commands/tasks/document.d.ts +5 -0
- package/dist/commands/tasks/document.d.ts.map +1 -0
- package/dist/commands/tasks/document.js +118 -0
- package/dist/commands/tasks/enhance.d.ts +3 -0
- package/dist/commands/tasks/enhance.d.ts.map +1 -0
- package/dist/commands/tasks/enhance.js +86 -0
- package/dist/commands/tasks/execute.d.ts +3 -0
- package/dist/commands/tasks/execute.d.ts.map +1 -0
- package/dist/commands/tasks/execute.js +33 -0
- package/dist/commands/tasks/index.d.ts +16 -0
- package/dist/commands/tasks/index.d.ts.map +1 -0
- package/dist/commands/tasks/index.js +31 -0
- package/dist/commands/tasks/list.d.ts +3 -0
- package/dist/commands/tasks/list.d.ts.map +1 -0
- package/dist/commands/tasks/list.js +27 -0
- package/dist/commands/tasks/next.d.ts +3 -0
- package/dist/commands/tasks/next.d.ts.map +1 -0
- package/dist/commands/tasks/next.js +44 -0
- package/dist/commands/tasks/plan.d.ts +7 -0
- package/dist/commands/tasks/plan.d.ts.map +1 -0
- package/dist/commands/tasks/plan.js +131 -0
- package/dist/commands/tasks/show.d.ts +3 -0
- package/dist/commands/tasks/show.d.ts.map +1 -0
- package/dist/commands/tasks/show.js +23 -0
- package/dist/commands/tasks/split.d.ts +3 -0
- package/dist/commands/tasks/split.d.ts.map +1 -0
- package/dist/commands/tasks/split.js +95 -0
- package/dist/commands/tasks/status.d.ts +3 -0
- package/dist/commands/tasks/status.d.ts.map +1 -0
- package/dist/commands/tasks/status.js +26 -0
- package/dist/commands/tasks/subtasks.d.ts +3 -0
- package/dist/commands/tasks/subtasks.d.ts.map +1 -0
- package/dist/commands/tasks/subtasks.js +35 -0
- package/dist/commands/tasks/tags.d.ts +4 -0
- package/dist/commands/tasks/tags.d.ts.map +1 -0
- package/dist/commands/tasks/tags.js +37 -0
- package/dist/commands/tasks/tree.d.ts +3 -0
- package/dist/commands/tasks/tree.d.ts.map +1 -0
- package/dist/commands/tasks/tree.js +20 -0
- package/dist/commands/tasks/update.d.ts +3 -0
- package/dist/commands/tasks/update.d.ts.map +1 -0
- package/dist/commands/tasks/update.js +35 -0
- package/dist/commands/tasks.d.ts.map +1 -1
- package/dist/commands/tasks.js +23 -594
- package/dist/commands/workflow.d.ts +4 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +434 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/lib/ai-service/ai-operations.d.ts +5 -3
- package/dist/lib/ai-service/ai-operations.d.ts.map +1 -1
- package/dist/lib/ai-service/ai-operations.js +231 -30
- package/dist/lib/ai-service/filesystem-tools.d.ts +69 -0
- package/dist/lib/ai-service/filesystem-tools.d.ts.map +1 -0
- package/dist/lib/ai-service/filesystem-tools.js +70 -0
- package/dist/lib/ai-service/research-tools.d.ts.map +1 -1
- package/dist/lib/ai-service/research-tools.js +2 -2
- package/dist/lib/context-builder.d.ts +2 -1
- package/dist/lib/context-builder.d.ts.map +1 -1
- package/dist/lib/context-builder.js +3 -8
- package/dist/lib/executors/claude-code-executor.d.ts +6 -0
- package/dist/lib/executors/claude-code-executor.d.ts.map +1 -0
- package/dist/lib/executors/claude-code-executor.js +41 -0
- package/dist/lib/executors/codex-executor.d.ts +6 -0
- package/dist/lib/executors/codex-executor.d.ts.map +1 -0
- package/dist/lib/executors/codex-executor.js +41 -0
- package/dist/lib/executors/executor-factory.d.ts.map +1 -1
- package/dist/lib/executors/executor-factory.js +6 -3
- package/dist/lib/executors/gemini-executor.d.ts +6 -0
- package/dist/lib/executors/gemini-executor.d.ts.map +1 -0
- package/dist/lib/executors/gemini-executor.js +41 -0
- package/dist/lib/executors/opencode-executor.d.ts.map +1 -1
- package/dist/lib/executors/opencode-executor.js +2 -3
- package/dist/lib/hooks/logger.d.ts +2 -0
- package/dist/lib/hooks/logger.d.ts.map +1 -0
- package/dist/lib/hooks/logger.js +27 -0
- package/dist/lib/hooks.d.ts +64 -0
- package/dist/lib/hooks.d.ts.map +1 -0
- package/dist/lib/hooks.js +60 -0
- package/dist/lib/index.d.ts +18 -17
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +3 -3
- package/dist/lib/prompt-builder.d.ts +8 -0
- package/dist/lib/prompt-builder.d.ts.map +1 -1
- package/dist/lib/prompt-builder.js +110 -4
- package/dist/lib/{storage.d.ts ā storage/file-system.d.ts} +4 -3
- package/dist/lib/storage/file-system.d.ts.map +1 -0
- package/dist/lib/{storage.js ā storage/file-system.js} +141 -152
- package/dist/lib/storage/types.d.ts +43 -0
- package/dist/lib/storage/types.d.ts.map +1 -0
- package/dist/lib/storage/types.js +2 -0
- package/dist/lib/task-execution.d.ts.map +1 -1
- package/dist/lib/task-execution.js +63 -14
- package/dist/prompts/workflow-assistance.d.ts +32 -0
- package/dist/prompts/workflow-assistance.d.ts.map +1 -0
- package/dist/prompts/workflow-assistance.js +130 -0
- package/dist/services/prd.d.ts +2 -0
- package/dist/services/prd.d.ts.map +1 -1
- package/dist/services/prd.js +4 -4
- package/dist/services/tasks.d.ts +13 -6
- package/dist/services/tasks.d.ts.map +1 -1
- package/dist/services/tasks.js +202 -88
- package/dist/services/workflow-ai-assistant.d.ts +74 -0
- package/dist/services/workflow-ai-assistant.d.ts.map +1 -0
- package/dist/services/workflow-ai-assistant.js +223 -0
- package/dist/test/hooks.test.d.ts +2 -0
- package/dist/test/hooks.test.d.ts.map +1 -0
- package/dist/test/hooks.test.js +58 -0
- package/dist/test/storage.test.js +16 -16
- package/dist/types/options.d.ts +35 -0
- package/dist/types/options.d.ts.map +1 -1
- package/dist/utils/ai-service-factory.d.ts +5 -5
- package/dist/utils/ai-service-factory.d.ts.map +1 -1
- package/dist/utils/ai-service-factory.js +4 -3
- package/dist/utils/workflow-prompts.d.ts +17 -0
- package/dist/utils/workflow-prompts.d.ts.map +1 -0
- package/dist/utils/workflow-prompts.js +88 -0
- package/package.json +2 -2
- package/dist/lib/storage.d.ts.map +0 -1
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.workflowCommand = void 0;
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const path_1 = require("path");
|
|
12
|
+
const config_1 = require("../lib/config");
|
|
13
|
+
const prd_1 = require("../services/prd");
|
|
14
|
+
const tasks_1 = require("../services/tasks");
|
|
15
|
+
const workflow_ai_assistant_1 = require("../services/workflow-ai-assistant");
|
|
16
|
+
const workflow_prompts_1 = require("../utils/workflow-prompts");
|
|
17
|
+
const streaming_options_1 = require("../utils/streaming-options");
|
|
18
|
+
const progress_1 = require("../cli/display/progress");
|
|
19
|
+
exports.workflowCommand = new commander_1.Command("workflow")
|
|
20
|
+
.description("Interactive workflow for complete project setup and task management")
|
|
21
|
+
.option("--stream", "Show streaming AI output")
|
|
22
|
+
.option("--ai-provider <provider>", "AI provider override")
|
|
23
|
+
.option("--ai-model <model>", "AI model override")
|
|
24
|
+
.option("--ai-key <key>", "AI API key override")
|
|
25
|
+
.action(async (options) => {
|
|
26
|
+
try {
|
|
27
|
+
console.log(chalk_1.default.blue.bold("\nš Task-O-Matic Interactive Workflow\n"));
|
|
28
|
+
console.log(chalk_1.default.gray("This wizard will guide you through:"));
|
|
29
|
+
console.log(chalk_1.default.gray(" 1. Project initialization & bootstrap"));
|
|
30
|
+
console.log(chalk_1.default.gray(" 2. PRD definition"));
|
|
31
|
+
console.log(chalk_1.default.gray(" 3. PRD refinement"));
|
|
32
|
+
console.log(chalk_1.default.gray(" 4. Task generation"));
|
|
33
|
+
console.log(chalk_1.default.gray(" 5. Task splitting\n"));
|
|
34
|
+
const state = {
|
|
35
|
+
initialized: false,
|
|
36
|
+
currentStep: "initialize",
|
|
37
|
+
projectDir: process.cwd(),
|
|
38
|
+
};
|
|
39
|
+
// Store AI options for later use
|
|
40
|
+
const aiOptions = {
|
|
41
|
+
aiProvider: options.aiProvider,
|
|
42
|
+
aiModel: options.aiModel,
|
|
43
|
+
aiKey: options.aiKey,
|
|
44
|
+
};
|
|
45
|
+
const streamingOptions = (0, streaming_options_1.createStreamingOptions)(options.stream, "Workflow");
|
|
46
|
+
// Step 1: Initialize/Bootstrap
|
|
47
|
+
await stepInitialize(state, aiOptions, streamingOptions);
|
|
48
|
+
// Step 2: Define PRD
|
|
49
|
+
await stepDefinePRD(state, aiOptions, streamingOptions);
|
|
50
|
+
// Step 3: Refine PRD
|
|
51
|
+
await stepRefinePRD(state, aiOptions, streamingOptions);
|
|
52
|
+
// Step 4: Generate Tasks
|
|
53
|
+
await stepGenerateTasks(state, aiOptions, streamingOptions);
|
|
54
|
+
// Step 5: Split Tasks
|
|
55
|
+
await stepSplitTasks(state, aiOptions, streamingOptions);
|
|
56
|
+
// Complete
|
|
57
|
+
state.currentStep = "complete";
|
|
58
|
+
console.log(chalk_1.default.green.bold("\nā
Workflow Complete!\n"));
|
|
59
|
+
console.log(chalk_1.default.cyan("Next steps:"));
|
|
60
|
+
console.log(chalk_1.default.gray(" ⢠Review your tasks: task-o-matic tasks list"));
|
|
61
|
+
console.log(chalk_1.default.gray(" ⢠View task tree: task-o-matic tasks tree"));
|
|
62
|
+
console.log(chalk_1.default.gray(" ⢠Get next task: task-o-matic tasks next"));
|
|
63
|
+
console.log(chalk_1.default.gray(" ⢠Execute a task: task-o-matic tasks execute <task-id>\n"));
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
(0, progress_1.displayError)(error);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* Step 1: Initialize/Bootstrap
|
|
72
|
+
*/
|
|
73
|
+
async function stepInitialize(state, aiOptions, streamingOptions) {
|
|
74
|
+
console.log(chalk_1.default.blue.bold("\nš¦ Step 1: Project Initialization\n"));
|
|
75
|
+
// Check if already initialized
|
|
76
|
+
const taskOMaticDir = config_1.configManager.getTaskOMaticDir();
|
|
77
|
+
const alreadyInitialized = (0, fs_1.existsSync)(taskOMaticDir);
|
|
78
|
+
if (alreadyInitialized) {
|
|
79
|
+
console.log(chalk_1.default.yellow("ā Project already initialized"));
|
|
80
|
+
const useExisting = await (0, workflow_prompts_1.confirmPrompt)("Use existing configuration?", true);
|
|
81
|
+
if (useExisting) {
|
|
82
|
+
state.initialized = true;
|
|
83
|
+
state.currentStep = "define-prd";
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const shouldInitialize = await (0, workflow_prompts_1.confirmPrompt)("Initialize a new task-o-matic project?", true);
|
|
88
|
+
if (!shouldInitialize) {
|
|
89
|
+
console.log(chalk_1.default.yellow("ā Skipping initialization"));
|
|
90
|
+
state.initialized = false;
|
|
91
|
+
state.currentStep = "define-prd";
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
// Choose initialization method
|
|
95
|
+
let initMethod = await (0, workflow_prompts_1.selectPrompt)("How would you like to configure your project?", [
|
|
96
|
+
{ name: "Quick start (recommended defaults)", value: "quick" },
|
|
97
|
+
{ name: "Custom configuration", value: "custom" },
|
|
98
|
+
{ name: "AI-assisted (describe your project)", value: "ai" },
|
|
99
|
+
]);
|
|
100
|
+
let config;
|
|
101
|
+
if (initMethod === "ai") {
|
|
102
|
+
console.log(chalk_1.default.cyan("\nš¤ AI-Assisted Configuration\n"));
|
|
103
|
+
const description = await (0, workflow_prompts_1.textInputPrompt)("Describe your project (e.g., 'A SaaS app for team collaboration with real-time features'):");
|
|
104
|
+
console.log(chalk_1.default.gray("\n Analyzing your requirements...\n"));
|
|
105
|
+
config = await workflow_ai_assistant_1.workflowAIAssistant.assistInitConfig({
|
|
106
|
+
userDescription: description,
|
|
107
|
+
aiOptions,
|
|
108
|
+
streamingOptions,
|
|
109
|
+
});
|
|
110
|
+
console.log(chalk_1.default.green("\nā AI Recommendations:"));
|
|
111
|
+
console.log(chalk_1.default.gray(` Project: ${config.projectName}`));
|
|
112
|
+
console.log(chalk_1.default.gray(` AI Provider: ${config.aiProvider}`));
|
|
113
|
+
console.log(chalk_1.default.gray(` Frontend: ${config.frontend || "none"}`));
|
|
114
|
+
console.log(chalk_1.default.gray(` Backend: ${config.backend || "none"}`));
|
|
115
|
+
console.log(chalk_1.default.gray(` Database: ${config.database || "none"}`));
|
|
116
|
+
console.log(chalk_1.default.gray(` Auth: ${config.auth ? "yes" : "no"}`));
|
|
117
|
+
if (config.reasoning) {
|
|
118
|
+
console.log(chalk_1.default.gray(`\n ${config.reasoning}\n`));
|
|
119
|
+
}
|
|
120
|
+
const acceptRecommendation = await (0, workflow_prompts_1.confirmPrompt)("Accept these recommendations?", true);
|
|
121
|
+
if (!acceptRecommendation) {
|
|
122
|
+
console.log(chalk_1.default.yellow("ā Falling back to custom configuration"));
|
|
123
|
+
initMethod = "custom";
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (initMethod === "quick") {
|
|
127
|
+
config = {
|
|
128
|
+
projectName: "my-project",
|
|
129
|
+
aiProvider: "openrouter",
|
|
130
|
+
aiModel: "anthropic/claude-3.5-sonnet",
|
|
131
|
+
frontend: "next",
|
|
132
|
+
backend: "hono",
|
|
133
|
+
database: "sqlite",
|
|
134
|
+
auth: true,
|
|
135
|
+
reasoning: "Modern, well-supported stack",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
else if (initMethod === "custom") {
|
|
139
|
+
config = {
|
|
140
|
+
projectName: await (0, workflow_prompts_1.textInputPrompt)("Project name:", "my-project"),
|
|
141
|
+
aiProvider: await (0, workflow_prompts_1.selectPrompt)("AI Provider:", [
|
|
142
|
+
"openrouter",
|
|
143
|
+
"anthropic",
|
|
144
|
+
"openai",
|
|
145
|
+
"custom",
|
|
146
|
+
]),
|
|
147
|
+
aiModel: await (0, workflow_prompts_1.textInputPrompt)("AI Model:", "anthropic/claude-3.5-sonnet"),
|
|
148
|
+
};
|
|
149
|
+
const shouldBootstrap = await (0, workflow_prompts_1.confirmPrompt)("Bootstrap with Better-T-Stack?", true);
|
|
150
|
+
if (shouldBootstrap) {
|
|
151
|
+
config.frontend = await (0, workflow_prompts_1.selectPrompt)("Frontend framework:", [
|
|
152
|
+
"next",
|
|
153
|
+
"tanstack-router",
|
|
154
|
+
"react-router",
|
|
155
|
+
"vite-react",
|
|
156
|
+
"remix",
|
|
157
|
+
]);
|
|
158
|
+
config.backend = await (0, workflow_prompts_1.selectPrompt)("Backend framework:", [
|
|
159
|
+
"hono",
|
|
160
|
+
"express",
|
|
161
|
+
"elysia",
|
|
162
|
+
"fastify",
|
|
163
|
+
]);
|
|
164
|
+
config.database = await (0, workflow_prompts_1.selectPrompt)("Database:", [
|
|
165
|
+
"sqlite",
|
|
166
|
+
"postgres",
|
|
167
|
+
"mysql",
|
|
168
|
+
"mongodb",
|
|
169
|
+
"turso",
|
|
170
|
+
"neon",
|
|
171
|
+
]);
|
|
172
|
+
config.auth = await (0, workflow_prompts_1.confirmPrompt)("Include authentication?", true);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Initialize project
|
|
176
|
+
console.log(chalk_1.default.cyan("\n Initializing project...\n"));
|
|
177
|
+
// Create .task-o-matic directory
|
|
178
|
+
if (!(0, fs_1.existsSync)(taskOMaticDir)) {
|
|
179
|
+
(0, fs_1.mkdirSync)(taskOMaticDir, { recursive: true });
|
|
180
|
+
["tasks", "prd", "logs"].forEach((dir) => {
|
|
181
|
+
(0, fs_1.mkdirSync)((0, path_1.join)(taskOMaticDir, dir), { recursive: true });
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
// Save configuration
|
|
185
|
+
config_1.configManager.setConfig({
|
|
186
|
+
ai: {
|
|
187
|
+
provider: config.aiProvider, // Cast to satisfy AIProvider type
|
|
188
|
+
model: config.aiModel,
|
|
189
|
+
maxTokens: 32768,
|
|
190
|
+
temperature: 0.5,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
config_1.configManager.save();
|
|
194
|
+
console.log(chalk_1.default.green("ā Project initialized"));
|
|
195
|
+
// Bootstrap if configured
|
|
196
|
+
if (config.frontend || config.backend) {
|
|
197
|
+
const shouldBootstrap = await (0, workflow_prompts_1.confirmPrompt)("Bootstrap project now?", true);
|
|
198
|
+
if (shouldBootstrap) {
|
|
199
|
+
console.log(chalk_1.default.cyan("\n Bootstrapping with Better-T-Stack...\n"));
|
|
200
|
+
console.log(chalk_1.default.gray(" (This may take a few minutes)\n"));
|
|
201
|
+
// Note: Actual bootstrap would call Better-T-Stack CLI
|
|
202
|
+
// For now, we'll just note the configuration
|
|
203
|
+
const btsConfig = {
|
|
204
|
+
projectName: config.projectName,
|
|
205
|
+
frontend: config.frontend,
|
|
206
|
+
backend: config.backend,
|
|
207
|
+
database: config.database,
|
|
208
|
+
auth: config.auth,
|
|
209
|
+
};
|
|
210
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(taskOMaticDir, "bts-config.json"), JSON.stringify(btsConfig, null, 2));
|
|
211
|
+
console.log(chalk_1.default.yellow("ā¹ Bootstrap configuration saved"));
|
|
212
|
+
console.log(chalk_1.default.gray(" Run 'task-o-matic init bootstrap' to complete setup\n"));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
state.initialized = true;
|
|
216
|
+
state.projectName = config.projectName;
|
|
217
|
+
state.aiConfig = {
|
|
218
|
+
provider: config.aiProvider,
|
|
219
|
+
model: config.aiModel,
|
|
220
|
+
};
|
|
221
|
+
state.currentStep = "define-prd";
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Step 2: Define PRD
|
|
225
|
+
*/
|
|
226
|
+
async function stepDefinePRD(state, aiOptions, streamingOptions) {
|
|
227
|
+
console.log(chalk_1.default.blue.bold("\nš Step 2: Define PRD\n"));
|
|
228
|
+
const prdMethod = await (0, workflow_prompts_1.selectPrompt)("How would you like to define your PRD?", [
|
|
229
|
+
{ name: "Upload existing file", value: "upload" },
|
|
230
|
+
{ name: "Write manually (open editor)", value: "manual" },
|
|
231
|
+
{ name: "AI-assisted creation", value: "ai" },
|
|
232
|
+
{ name: "Skip (use existing PRD)", value: "skip" },
|
|
233
|
+
]);
|
|
234
|
+
const taskOMaticDir = config_1.configManager.getTaskOMaticDir();
|
|
235
|
+
const prdDir = (0, path_1.join)(taskOMaticDir, "prd");
|
|
236
|
+
if (prdMethod === "skip") {
|
|
237
|
+
console.log(chalk_1.default.yellow("ā Skipping PRD definition"));
|
|
238
|
+
state.currentStep = "refine-prd";
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
let prdContent = "";
|
|
242
|
+
let prdFilename = "prd.md";
|
|
243
|
+
if (prdMethod === "upload") {
|
|
244
|
+
const filePath = await (0, workflow_prompts_1.textInputPrompt)("Path to PRD file:");
|
|
245
|
+
if (!(0, fs_1.existsSync)(filePath)) {
|
|
246
|
+
console.log(chalk_1.default.red(`ā File not found: ${filePath}`));
|
|
247
|
+
return stepDefinePRD(state, aiOptions, streamingOptions);
|
|
248
|
+
}
|
|
249
|
+
prdContent = (0, fs_1.readFileSync)(filePath, "utf-8");
|
|
250
|
+
prdFilename = filePath.split("/").pop() || "prd.md";
|
|
251
|
+
}
|
|
252
|
+
else if (prdMethod === "manual") {
|
|
253
|
+
console.log(chalk_1.default.gray("\n Opening editor...\n"));
|
|
254
|
+
prdContent = await (0, workflow_prompts_1.editorPrompt)("Write your PRD (save and close editor when done):", "# Product Requirements Document\n\n## Overview\n\n## Objectives\n\n## Features\n\n");
|
|
255
|
+
}
|
|
256
|
+
else if (prdMethod === "ai") {
|
|
257
|
+
console.log(chalk_1.default.cyan("\nš¤ AI-Assisted PRD Creation\n"));
|
|
258
|
+
const description = await (0, workflow_prompts_1.textInputPrompt)("Describe your product in detail:");
|
|
259
|
+
console.log(chalk_1.default.gray("\n Generating PRD...\n"));
|
|
260
|
+
prdContent = await workflow_ai_assistant_1.workflowAIAssistant.assistPRDCreation({
|
|
261
|
+
userDescription: description,
|
|
262
|
+
aiOptions,
|
|
263
|
+
streamingOptions,
|
|
264
|
+
});
|
|
265
|
+
console.log(chalk_1.default.green("\nā PRD generated"));
|
|
266
|
+
console.log(chalk_1.default.gray("\n" + prdContent.substring(0, 500) + "...\n"));
|
|
267
|
+
const acceptPRD = await (0, workflow_prompts_1.confirmPrompt)("Accept this PRD?", true);
|
|
268
|
+
if (!acceptPRD) {
|
|
269
|
+
console.log(chalk_1.default.yellow("ā Regenerating..."));
|
|
270
|
+
return stepDefinePRD(state, aiOptions, streamingOptions);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// Save PRD
|
|
274
|
+
const prdPath = (0, path_1.join)(prdDir, prdFilename);
|
|
275
|
+
(0, fs_1.writeFileSync)(prdPath, prdContent);
|
|
276
|
+
console.log(chalk_1.default.green(`ā PRD saved to ${prdPath}`));
|
|
277
|
+
state.prdFile = prdPath;
|
|
278
|
+
state.prdContent = prdContent;
|
|
279
|
+
state.currentStep = "refine-prd";
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Step 3: Refine PRD
|
|
283
|
+
*/
|
|
284
|
+
async function stepRefinePRD(state, aiOptions, streamingOptions) {
|
|
285
|
+
console.log(chalk_1.default.blue.bold("\n⨠Step 3: Refine PRD\n"));
|
|
286
|
+
if (!state.prdFile) {
|
|
287
|
+
console.log(chalk_1.default.yellow("ā No PRD file found, skipping refinement"));
|
|
288
|
+
state.currentStep = "generate-tasks";
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const shouldRefine = await (0, workflow_prompts_1.confirmPrompt)("Refine your PRD?", false);
|
|
292
|
+
if (!shouldRefine) {
|
|
293
|
+
console.log(chalk_1.default.gray(" Skipping refinement"));
|
|
294
|
+
state.currentStep = "generate-tasks";
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const refineMethod = await (0, workflow_prompts_1.selectPrompt)("How would you like to refine?", [
|
|
298
|
+
{ name: "Manual editing (open editor)", value: "manual" },
|
|
299
|
+
{ name: "AI-assisted refinement", value: "ai" },
|
|
300
|
+
{ name: "Skip", value: "skip" },
|
|
301
|
+
]);
|
|
302
|
+
if (refineMethod === "skip") {
|
|
303
|
+
state.currentStep = "generate-tasks";
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
let refinedContent = state.prdContent || (0, fs_1.readFileSync)(state.prdFile, "utf-8");
|
|
307
|
+
if (refineMethod === "manual") {
|
|
308
|
+
console.log(chalk_1.default.gray("\n Opening editor...\n"));
|
|
309
|
+
refinedContent = await (0, workflow_prompts_1.editorPrompt)("Edit your PRD (save and close when done):", refinedContent);
|
|
310
|
+
}
|
|
311
|
+
else if (refineMethod === "ai") {
|
|
312
|
+
console.log(chalk_1.default.cyan("\nš¤ AI-Assisted Refinement\n"));
|
|
313
|
+
const feedback = await (0, workflow_prompts_1.textInputPrompt)("What would you like to improve? (e.g., 'Add more technical details', 'Focus on MVP features'):");
|
|
314
|
+
console.log(chalk_1.default.gray("\n Refining PRD...\n"));
|
|
315
|
+
refinedContent = await workflow_ai_assistant_1.workflowAIAssistant.assistPRDRefinement({
|
|
316
|
+
currentPRD: refinedContent,
|
|
317
|
+
userFeedback: feedback,
|
|
318
|
+
aiOptions,
|
|
319
|
+
streamingOptions,
|
|
320
|
+
});
|
|
321
|
+
console.log(chalk_1.default.green("\nā PRD refined"));
|
|
322
|
+
console.log(chalk_1.default.gray("\n" + refinedContent.substring(0, 500) + "...\n"));
|
|
323
|
+
const acceptRefinement = await (0, workflow_prompts_1.confirmPrompt)("Accept refinements?", true);
|
|
324
|
+
if (!acceptRefinement) {
|
|
325
|
+
console.log(chalk_1.default.yellow("ā Keeping original PRD"));
|
|
326
|
+
state.currentStep = "generate-tasks";
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// Save refined PRD
|
|
331
|
+
(0, fs_1.writeFileSync)(state.prdFile, refinedContent);
|
|
332
|
+
state.prdContent = refinedContent;
|
|
333
|
+
console.log(chalk_1.default.green(`ā PRD updated`));
|
|
334
|
+
state.currentStep = "generate-tasks";
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Step 4: Generate Tasks
|
|
338
|
+
*/
|
|
339
|
+
async function stepGenerateTasks(state, aiOptions, streamingOptions) {
|
|
340
|
+
console.log(chalk_1.default.blue.bold("\nšÆ Step 4: Generate Tasks\n"));
|
|
341
|
+
if (!state.prdFile) {
|
|
342
|
+
console.log(chalk_1.default.yellow("ā No PRD file found, skipping task generation"));
|
|
343
|
+
state.currentStep = "split-tasks";
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const shouldGenerate = await (0, workflow_prompts_1.confirmPrompt)("Generate tasks from PRD?", true);
|
|
347
|
+
if (!shouldGenerate) {
|
|
348
|
+
console.log(chalk_1.default.gray(" Skipping task generation"));
|
|
349
|
+
state.currentStep = "split-tasks";
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const generationMethod = await (0, workflow_prompts_1.selectPrompt)("Choose generation method:", [
|
|
353
|
+
{ name: "Standard parsing", value: "standard" },
|
|
354
|
+
{ name: "AI-assisted with custom instructions", value: "ai" },
|
|
355
|
+
]);
|
|
356
|
+
let customInstructions;
|
|
357
|
+
if (generationMethod === "ai") {
|
|
358
|
+
customInstructions = await (0, workflow_prompts_1.textInputPrompt)("Custom instructions (e.g., 'Focus on MVP features', 'Break into small tasks'):", "");
|
|
359
|
+
}
|
|
360
|
+
console.log(chalk_1.default.cyan("\n Parsing PRD and generating tasks...\n"));
|
|
361
|
+
const result = await prd_1.prdService.parsePRD({
|
|
362
|
+
file: state.prdFile,
|
|
363
|
+
workingDirectory: state.projectDir,
|
|
364
|
+
aiOptions,
|
|
365
|
+
messageOverride: customInstructions,
|
|
366
|
+
streamingOptions,
|
|
367
|
+
callbacks: {
|
|
368
|
+
onProgress: progress_1.displayProgress,
|
|
369
|
+
onError: progress_1.displayError,
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
console.log(chalk_1.default.green(`\nā Generated ${result.tasks.length} tasks`));
|
|
373
|
+
// Display tasks
|
|
374
|
+
console.log(chalk_1.default.blue("\n Created Tasks:\n"));
|
|
375
|
+
result.tasks.forEach((task, index) => {
|
|
376
|
+
console.log(chalk_1.default.gray(` ${index + 1}. ${task.title} ${task.estimatedEffort ? `(${task.estimatedEffort})` : ""}`));
|
|
377
|
+
});
|
|
378
|
+
state.tasks = result.tasks.map((t) => ({
|
|
379
|
+
id: t.id,
|
|
380
|
+
title: t.title,
|
|
381
|
+
description: t.description,
|
|
382
|
+
}));
|
|
383
|
+
state.currentStep = "split-tasks";
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Step 5: Split Complex Tasks
|
|
387
|
+
*/
|
|
388
|
+
async function stepSplitTasks(state, aiOptions, streamingOptions) {
|
|
389
|
+
console.log(chalk_1.default.blue.bold("\nš Step 5: Split Complex Tasks\n"));
|
|
390
|
+
if (!state.tasks || state.tasks.length === 0) {
|
|
391
|
+
console.log(chalk_1.default.yellow("ā No tasks found, skipping splitting"));
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const shouldSplit = await (0, workflow_prompts_1.confirmPrompt)("Split any complex tasks into subtasks?", false);
|
|
395
|
+
if (!shouldSplit) {
|
|
396
|
+
console.log(chalk_1.default.gray(" Skipping task splitting"));
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
// Show tasks with effort estimates
|
|
400
|
+
const tasksToSplit = await (0, workflow_prompts_1.multiSelectPrompt)("Select tasks to split:", state.tasks.map((t) => ({
|
|
401
|
+
name: `${t.title}${t.description ? ` - ${t.description.substring(0, 50)}...` : ""}`,
|
|
402
|
+
value: t.id,
|
|
403
|
+
})));
|
|
404
|
+
if (tasksToSplit.length === 0) {
|
|
405
|
+
console.log(chalk_1.default.gray(" No tasks selected"));
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
for (const taskId of tasksToSplit) {
|
|
409
|
+
const task = state.tasks.find((t) => t.id === taskId);
|
|
410
|
+
if (!task)
|
|
411
|
+
continue;
|
|
412
|
+
console.log(chalk_1.default.cyan(`\n Splitting: ${task.title}\n`));
|
|
413
|
+
const splitMethod = await (0, workflow_prompts_1.selectPrompt)("Split method:", [
|
|
414
|
+
{ name: "Standard AI split", value: "standard" },
|
|
415
|
+
{ name: "Custom instructions", value: "custom" },
|
|
416
|
+
]);
|
|
417
|
+
let customInstructions;
|
|
418
|
+
if (splitMethod === "custom") {
|
|
419
|
+
customInstructions = await (0, workflow_prompts_1.textInputPrompt)("Custom instructions (e.g., 'Break into 2-4 hour chunks'):", "");
|
|
420
|
+
}
|
|
421
|
+
try {
|
|
422
|
+
const result = await tasks_1.taskService.splitTask(taskId, aiOptions, undefined, // promptOverride
|
|
423
|
+
customInstructions, streamingOptions);
|
|
424
|
+
console.log(chalk_1.default.green(` ā Created ${result.subtasks.length} subtasks`));
|
|
425
|
+
result.subtasks.forEach((subtask, index) => {
|
|
426
|
+
console.log(chalk_1.default.gray(` ${index + 1}. ${subtask.title}`));
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
console.log(chalk_1.default.red(` ā Failed to split task: ${error}`));
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
console.log(chalk_1.default.green("\nā Task splitting complete"));
|
|
434
|
+
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AA8C9B;;;GAGG;AACH,eAAO,MAAM,MAAM,qBAUlB,CAAC;AAEF;;GAEG;AACH,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ const tasks_1 = require("./commands/tasks");
|
|
|
17
17
|
const prd_1 = require("./commands/prd");
|
|
18
18
|
const init_1 = require("./commands/init");
|
|
19
19
|
const prompt_1 = require("./commands/prompt");
|
|
20
|
+
const workflow_1 = require("./commands/workflow");
|
|
20
21
|
const config_2 = require("./lib/config");
|
|
21
22
|
const program = new commander_1.Command();
|
|
22
23
|
exports.program = program;
|
|
@@ -31,6 +32,7 @@ program.addCommand(tasks_1.tasksCommand);
|
|
|
31
32
|
program.addCommand(prd_1.prdCommand);
|
|
32
33
|
program.addCommand(prompt_1.promptCommand);
|
|
33
34
|
program.addCommand(init_1.initCommand);
|
|
35
|
+
program.addCommand(workflow_1.workflowCommand);
|
|
34
36
|
// Default action - show help
|
|
35
37
|
program.action(() => {
|
|
36
38
|
console.log(chalk_1.default.blue("š AI-Powered Task Management CLI"));
|
|
@@ -47,7 +49,7 @@ program.action(() => {
|
|
|
47
49
|
// Error handling
|
|
48
50
|
program.on("command:*", (operands) => {
|
|
49
51
|
console.error(chalk_1.default.red(`Unknown command: ${operands[0]}`));
|
|
50
|
-
console.log(chalk_1.default.blue("Available commands: config, tasks, prd, prompt, init"));
|
|
52
|
+
console.log(chalk_1.default.blue("Available commands: config, tasks, prd, prompt, init, workflow"));
|
|
51
53
|
console.log(chalk_1.default.blue("Use --help for available commands"));
|
|
52
54
|
process.exit(1);
|
|
53
55
|
});
|
|
@@ -5,14 +5,16 @@ export declare class AIOperations {
|
|
|
5
5
|
private retryHandler;
|
|
6
6
|
private modelProvider;
|
|
7
7
|
streamText(prompt: string, config?: Partial<AIConfig>, systemPrompt?: string, userMessage?: string, streamingOptions?: StreamingOptions, retryConfig?: Partial<RetryConfig>): Promise<string>;
|
|
8
|
-
parsePRD(prdContent: string, config?: Partial<AIConfig>, promptOverride?: string, userMessage?: string, streamingOptions?: StreamingOptions, retryConfig?: Partial<RetryConfig>, workingDirectory?: string
|
|
9
|
-
|
|
8
|
+
parsePRD(prdContent: string, config?: Partial<AIConfig>, promptOverride?: string, userMessage?: string, streamingOptions?: StreamingOptions, retryConfig?: Partial<RetryConfig>, workingDirectory?: string, // Working directory passed from service layer
|
|
9
|
+
enableFilesystemTools?: boolean): Promise<AIPRDParseResult>;
|
|
10
|
+
breakdownTask(task: Task, config?: Partial<AIConfig>, promptOverride?: string, userMessage?: string, streamingOptions?: StreamingOptions, retryConfig?: Partial<RetryConfig>, fullContent?: string, stackInfo?: string, existingSubtasks?: Task[], enableFilesystemTools?: boolean): Promise<Array<{
|
|
10
11
|
title: string;
|
|
11
12
|
content: string;
|
|
12
13
|
estimatedEffort?: string;
|
|
13
14
|
}>>;
|
|
14
15
|
enhanceTask(title: string, description?: string, config?: Partial<AIConfig>, promptOverride?: string, userMessage?: string, taskId?: string, streamingOptions?: StreamingOptions, retryConfig?: Partial<RetryConfig>): Promise<string>;
|
|
15
|
-
reworkPRD(prdContent: string, feedback: string, config?: Partial<AIConfig>, promptOverride?: string, userMessage?: string, streamingOptions?: StreamingOptions, retryConfig?: Partial<RetryConfig>, workingDirectory?: string
|
|
16
|
+
reworkPRD(prdContent: string, feedback: string, config?: Partial<AIConfig>, promptOverride?: string, userMessage?: string, streamingOptions?: StreamingOptions, retryConfig?: Partial<RetryConfig>, workingDirectory?: string, // Working directory passed from service layer
|
|
17
|
+
enableFilesystemTools?: boolean): Promise<string>;
|
|
16
18
|
enhanceTaskWithDocumentation(taskId: string, taskTitle: string, taskDescription: string, stackInfo?: string, streamingOptions?: StreamingOptions, retryConfig?: Partial<RetryConfig>, config?: Partial<AIConfig>, existingResearch?: Record<string, Array<{
|
|
17
19
|
query: string;
|
|
18
20
|
doc: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-operations.d.ts","sourceRoot":"","sources":["../../../src/lib/ai-service/ai-operations.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,QAAQ,EACR,IAAI,EACJ,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,WAAW,EAGX,iBAAiB,EAClB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ai-operations.d.ts","sourceRoot":"","sources":["../../../src/lib/ai-service/ai-operations.ts"],"names":[],"mappings":"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"}
|