task-o-matic 0.0.9 → 0.0.11

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 (110) hide show
  1. package/dist/cli/display/progress.d.ts +1 -1
  2. package/dist/cli/display/progress.d.ts.map +1 -1
  3. package/dist/cli/display/progress.js +16 -13
  4. package/dist/commands/benchmark.js +70 -2
  5. package/dist/commands/init.js +48 -27
  6. package/dist/commands/prd.d.ts.map +1 -1
  7. package/dist/commands/prd.js +201 -0
  8. package/dist/commands/tasks/execute-loop.d.ts.map +1 -1
  9. package/dist/commands/tasks/execute-loop.js +10 -0
  10. package/dist/commands/tasks/execute.d.ts.map +1 -1
  11. package/dist/commands/tasks/execute.js +4 -0
  12. package/dist/commands/workflow.d.ts.map +1 -1
  13. package/dist/commands/workflow.js +56 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -0
  16. package/dist/lib/ai-service/ai-operations.d.ts +13 -10
  17. package/dist/lib/ai-service/ai-operations.d.ts.map +1 -1
  18. package/dist/lib/ai-service/ai-operations.js +35 -995
  19. package/dist/lib/ai-service/base-operations.d.ts +13 -0
  20. package/dist/lib/ai-service/base-operations.d.ts.map +1 -0
  21. package/dist/lib/ai-service/base-operations.js +79 -0
  22. package/dist/lib/ai-service/documentation-operations.d.ts +18 -0
  23. package/dist/lib/ai-service/documentation-operations.d.ts.map +1 -0
  24. package/dist/lib/ai-service/documentation-operations.js +291 -0
  25. package/dist/lib/ai-service/prd-operations.d.ts +14 -0
  26. package/dist/lib/ai-service/prd-operations.d.ts.map +1 -0
  27. package/dist/lib/ai-service/prd-operations.js +405 -0
  28. package/dist/lib/ai-service/task-operations.d.ts +12 -0
  29. package/dist/lib/ai-service/task-operations.d.ts.map +1 -0
  30. package/dist/lib/ai-service/task-operations.js +225 -0
  31. package/dist/lib/benchmark/registry.d.ts.map +1 -1
  32. package/dist/lib/benchmark/registry.js +127 -0
  33. package/dist/lib/better-t-stack-cli.d.ts +4 -1
  34. package/dist/lib/better-t-stack-cli.d.ts.map +1 -1
  35. package/dist/lib/better-t-stack-cli.js +126 -5
  36. package/dist/lib/config.d.ts +13 -6
  37. package/dist/lib/config.d.ts.map +1 -1
  38. package/dist/lib/config.js +90 -48
  39. package/dist/lib/context-builder.d.ts +13 -1
  40. package/dist/lib/context-builder.d.ts.map +1 -1
  41. package/dist/lib/context-builder.js +68 -36
  42. package/dist/lib/executors/claude-code-executor.d.ts +5 -2
  43. package/dist/lib/executors/claude-code-executor.d.ts.map +1 -1
  44. package/dist/lib/executors/claude-code-executor.js +30 -3
  45. package/dist/lib/executors/codex-executor.d.ts +5 -2
  46. package/dist/lib/executors/codex-executor.d.ts.map +1 -1
  47. package/dist/lib/executors/codex-executor.js +30 -3
  48. package/dist/lib/executors/executor-factory.d.ts +2 -2
  49. package/dist/lib/executors/executor-factory.d.ts.map +1 -1
  50. package/dist/lib/executors/executor-factory.js +5 -5
  51. package/dist/lib/executors/gemini-executor.d.ts +5 -2
  52. package/dist/lib/executors/gemini-executor.d.ts.map +1 -1
  53. package/dist/lib/executors/gemini-executor.js +30 -3
  54. package/dist/lib/executors/opencode-executor.d.ts +5 -2
  55. package/dist/lib/executors/opencode-executor.d.ts.map +1 -1
  56. package/dist/lib/executors/opencode-executor.js +30 -7
  57. package/dist/lib/index.d.ts +5 -0
  58. package/dist/lib/index.d.ts.map +1 -1
  59. package/dist/lib/index.js +7 -1
  60. package/dist/lib/prompt-builder.d.ts.map +1 -1
  61. package/dist/lib/prompt-builder.js +1 -0
  62. package/dist/lib/storage/file-system.d.ts +3 -7
  63. package/dist/lib/storage/file-system.d.ts.map +1 -1
  64. package/dist/lib/storage/file-system.js +50 -230
  65. package/dist/lib/storage/storage-callbacks.d.ts +17 -0
  66. package/dist/lib/storage/storage-callbacks.d.ts.map +1 -0
  67. package/dist/lib/storage/storage-callbacks.js +94 -0
  68. package/dist/lib/task-execution.d.ts.map +1 -1
  69. package/dist/lib/task-execution.js +16 -9
  70. package/dist/lib/task-loop-execution.d.ts.map +1 -1
  71. package/dist/lib/task-loop-execution.js +207 -8
  72. package/dist/prompts/index.d.ts +2 -0
  73. package/dist/prompts/index.d.ts.map +1 -1
  74. package/dist/prompts/index.js +2 -0
  75. package/dist/prompts/prd-combination.d.ts +2 -0
  76. package/dist/prompts/prd-combination.d.ts.map +1 -0
  77. package/dist/prompts/prd-combination.js +35 -0
  78. package/dist/prompts/prd-generation.d.ts +2 -0
  79. package/dist/prompts/prd-generation.d.ts.map +1 -0
  80. package/dist/prompts/prd-generation.js +49 -0
  81. package/dist/services/prd.d.ts +43 -0
  82. package/dist/services/prd.d.ts.map +1 -1
  83. package/dist/services/prd.js +121 -0
  84. package/dist/services/workflow-ai-assistant.d.ts.map +1 -1
  85. package/dist/services/workflow-ai-assistant.js +1 -40
  86. package/dist/services/workflow.d.ts +10 -0
  87. package/dist/services/workflow.d.ts.map +1 -1
  88. package/dist/services/workflow.js +118 -40
  89. package/dist/test/hooks.test.js +19 -10
  90. package/dist/test/integration/callbacks.test.d.ts +2 -0
  91. package/dist/test/integration/callbacks.test.d.ts.map +1 -0
  92. package/dist/test/integration/callbacks.test.js +64 -0
  93. package/dist/test/task-loop-git.test.js +33 -0
  94. package/dist/test/validation.test.d.ts +2 -0
  95. package/dist/test/validation.test.d.ts.map +1 -0
  96. package/dist/test/validation.test.js +22 -0
  97. package/dist/types/callbacks.d.ts +9 -6
  98. package/dist/types/callbacks.d.ts.map +1 -1
  99. package/dist/types/index.d.ts +17 -2
  100. package/dist/types/index.d.ts.map +1 -1
  101. package/dist/types/workflow-options.d.ts +7 -0
  102. package/dist/types/workflow-options.d.ts.map +1 -1
  103. package/dist/utils/ai-service-factory.d.ts +15 -1
  104. package/dist/utils/ai-service-factory.d.ts.map +1 -1
  105. package/dist/utils/ai-service-factory.js +29 -1
  106. package/dist/utils/streaming-options.d.ts +1 -1
  107. package/dist/utils/streaming-options.d.ts.map +1 -1
  108. package/dist/utils/streaming-options.js +31 -18
  109. package/docs/agents/cli.md +191 -0
  110. package/package.json +3 -2
@@ -1,1016 +1,56 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.AIOperations = void 0;
37
- const ai_1 = require("ai");
38
- const prompt_builder_1 = require("../prompt-builder");
39
- const stack_formatter_1 = require("../../utils/stack-formatter");
40
- const prompts_1 = require("../../prompts");
41
- const ai_service_factory_1 = require("../../utils/ai-service-factory");
42
- const json_parser_1 = require("./json-parser");
43
- const mcp_client_1 = require("./mcp-client");
44
- const retry_handler_1 = require("./retry-handler");
45
- const model_provider_1 = require("./model-provider");
46
- const filesystem_tools_1 = require("./filesystem-tools");
47
- class AIOperations {
48
- jsonParser = new json_parser_1.JSONParser();
49
- context7Client = new mcp_client_1.Context7Client();
50
- retryHandler = new retry_handler_1.RetryHandler();
51
- modelProvider = new model_provider_1.ModelProvider();
52
- // private researchTools = new ResearchTools(); // COMMENTED OUT - TESTING
53
- async streamText(prompt, config, systemPrompt, userMessage, streamingOptions, retryConfig) {
54
- const aiConfig = { ...this.modelProvider.getAIConfig(), ...config };
55
- return this.retryHandler.executeWithRetry(async () => {
56
- const model = this.modelProvider.getModel(aiConfig);
57
- const result = (0, ai_1.streamText)({
58
- model,
59
- system: systemPrompt,
60
- messages: [{ role: "user", content: userMessage || prompt }],
61
- maxRetries: 0, // Disable built-in retries since we handle them manually
62
- onError: ({ error }) => {
63
- // Call user's error callback if provided
64
- streamingOptions?.onError?.(error);
65
- // Re-throw the FULL error to maintain existing error handling behavior
66
- throw error;
67
- },
68
- onChunk: streamingOptions?.onChunk
69
- ? ({ chunk }) => {
70
- if (chunk.type === "text-delta") {
71
- streamingOptions.onChunk(chunk.text);
72
- }
73
- else if (chunk.type === "tool-result" &&
74
- chunk.toolName === "get-library-docs") {
75
- const docs = chunk.output;
76
- if (docs && typeof docs === "object" && "content" in docs) {
77
- this.context7Client.saveContext7Documentation(chunk.input?.context7CompatibleLibraryID || "unknown", docs.content, chunk.input?.topic || "general");
78
- }
79
- else if (docs && typeof docs === "string") {
80
- this.context7Client.saveContext7Documentation(chunk.input?.context7CompatibleLibraryID || "unknown", docs, chunk.input?.topic || "general");
81
- }
82
- }
83
- }
84
- : undefined,
85
- onFinish: streamingOptions?.onFinish
86
- ? ({ text, finishReason, usage }) => {
87
- streamingOptions.onFinish({
88
- text,
89
- finishReason,
90
- usage,
91
- isAborted: false,
92
- });
93
- }
94
- : undefined,
95
- // Add reasoning configuration only for OpenRouter with explicit reasoning parameter
96
- ...(aiConfig.provider === "openrouter" &&
97
- aiConfig.reasoning &&
98
- aiConfig.reasoning.maxTokens
99
- ? {
100
- providerOptions: {
101
- openrouter: {
102
- reasoning: {
103
- max_tokens: aiConfig.reasoning.maxTokens,
104
- },
105
- },
106
- },
107
- }
108
- : {}),
109
- });
110
- let fullText = "";
111
- for await (const textPart of result.textStream) {
112
- fullText += textPart;
113
- }
114
- return fullText;
115
- }, retryConfig, "AI streaming");
116
- }
117
- async parsePRD(prdContent, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory, // Working directory passed from service layer
118
- enableFilesystemTools) {
119
- return this.retryHandler.executeWithRetry(async () => {
120
- // Get stack context for better PRD parsing using PromptBuilder
121
- // Pass working directory explicitly to avoid process.cwd() issues
122
- let stackInfo = "";
123
- try {
124
- stackInfo = await prompt_builder_1.PromptBuilder.detectStackInfo(workingDirectory);
125
- if (stackInfo === "Not detected") {
126
- stackInfo = "";
127
- }
128
- }
129
- catch (error) {
130
- // Stack info not available, will use empty string
131
- }
132
- // Use PromptBuilder if no prompt override provided
133
- let enhancedPrompt;
134
- if (promptOverride) {
135
- enhancedPrompt = promptOverride;
136
- }
137
- else {
138
- const variables = {
139
- PRD_CONTENT: prdContent,
140
- };
141
- // Only include stack info if we have it
142
- if (stackInfo) {
143
- variables.STACK_INFO = stackInfo;
144
- }
145
- const promptResult = prompt_builder_1.PromptBuilder.buildPrompt({
146
- name: "prd-parsing",
147
- type: "user",
148
- variables,
149
- });
150
- if (!promptResult.success) {
151
- throw new Error(`Failed to build PRD parsing prompt: ${promptResult.error}`);
152
- }
153
- enhancedPrompt = promptResult.prompt; // TypeScript: prompt is guaranteed when success is true
154
- }
155
- let response;
156
- if (enableFilesystemTools) {
157
- // Use filesystem tools when enabled
158
- const model = this.modelProvider.getModel({
159
- ...this.modelProvider.getAIConfig(),
160
- ...config,
161
- });
162
- const allTools = {
163
- ...filesystem_tools_1.filesystemTools,
164
- };
165
- const result = await (0, ai_1.streamText)({
166
- model,
167
- tools: allTools, // Filesystem tools for project analysis
168
- system: prompts_1.PRD_PARSING_SYSTEM_PROMPT +
169
- `
170
-
171
- You have access to filesystem tools that allow you to:
172
- - readFile: Read the contents of any file in the project
173
- - listDirectory: List contents of directories
174
-
175
- Use these tools to understand the project structure, existing code patterns, and dependencies when parsing the PRD and creating tasks.`,
176
- messages: [
177
- { role: "user", content: userMessage || enhancedPrompt },
178
- ],
179
- maxRetries: 0,
180
- onChunk: streamingOptions?.onChunk
181
- ? ({ chunk }) => {
182
- if (chunk.type === "text-delta") {
183
- streamingOptions.onChunk(chunk.text);
184
- }
185
- }
186
- : undefined,
187
- onFinish: streamingOptions?.onFinish
188
- ? ({ text, finishReason, usage }) => {
189
- streamingOptions.onFinish({
190
- text,
191
- finishReason,
192
- usage,
193
- isAborted: false,
194
- });
195
- }
196
- : undefined,
197
- });
198
- response = await result.text;
199
- }
200
- else {
201
- // Use standard streamText without tools
202
- response = await this.streamText("", // empty prompt since we use messages
203
- config, prompts_1.PRD_PARSING_SYSTEM_PROMPT, userMessage || enhancedPrompt, streamingOptions, { maxAttempts: 1 } // Disable retries here since we're handling them at the outer level
204
- );
205
- }
206
- // Parse JSON from response using proper typing
207
- const parseResult = this.jsonParser.parseJSONFromResponse(response);
208
- if (!parseResult.success) {
209
- throw new Error(parseResult.error || "Failed to parse PRD response");
210
- }
211
- const parsed = parseResult.data;
212
- // Transform to our format with proper IDs for dependencies
213
- const tasks = (parsed?.tasks || []).map((task, index) => {
214
- const taskId = task.id || (index + 1).toString();
215
- // Extract all AI-generated keys except the ones we handle separately
216
- const { title, description, content, effort, dependencies, ...extraData } = task;
217
- // Create comprehensive content from all AI data
218
- let fullContent = "";
219
- if (description || content) {
220
- fullContent = description || content || "";
221
- }
222
- // Add any extra AI-generated data as structured content
223
- if (Object.keys(extraData).length > 0) {
224
- fullContent += "\n\n## Additional AI-Generated Information\n";
225
- for (const [key, value] of Object.entries(extraData)) {
226
- fullContent += `\n**${key}:** ${JSON.stringify(value, null, 2)}`;
227
- }
228
- }
229
- return {
230
- id: taskId,
231
- title: task.title,
232
- description: (task.description || task.content || "").substring(0, 200) +
233
- ((task.description || task.content || "").length > 200
234
- ? "..."
235
- : ""),
236
- content: fullContent,
237
- status: "todo",
238
- createdAt: Date.now(),
239
- updatedAt: Date.now(),
240
- estimatedEffort: task.effort,
241
- dependencies: task.dependencies || [],
242
- tags: task.tags || [],
243
- };
244
- });
245
- return {
246
- tasks,
247
- summary: parsed?.summary || "PRD parsed successfully",
248
- estimatedDuration: parsed?.estimatedDuration || "Unknown",
249
- confidence: parsed?.confidence || 0.7,
250
- };
251
- }, retryConfig, "PRD parsing");
252
- }
4
+ const base_operations_1 = require("./base-operations");
5
+ const prd_operations_1 = require("./prd-operations");
6
+ const task_operations_1 = require("./task-operations");
7
+ const documentation_operations_1 = require("./documentation-operations");
8
+ /**
9
+ * Main AIOperations class that delegates to specialized operation classes.
10
+ * This provides a unified API for all AI operations while keeping the implementation modular.
11
+ */
12
+ class AIOperations extends base_operations_1.BaseOperations {
13
+ prdOps = new prd_operations_1.PRDOperations();
14
+ taskOps = new task_operations_1.TaskOperations();
15
+ docOps = new documentation_operations_1.DocumentationOperations();
16
+ // PRD Operations - Delegated to PRDOperations
17
+ async parsePRD(prdContent, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory, enableFilesystemTools) {
18
+ return this.prdOps.parsePRD(prdContent, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory, enableFilesystemTools);
19
+ }
20
+ // Task Operations - Delegated to TaskOperations
253
21
  async breakdownTask(task, config, promptOverride, userMessage, streamingOptions, retryConfig, fullContent, stackInfo, existingSubtasks, enableFilesystemTools) {
254
- return this.retryHandler.executeWithRetry(async () => {
255
- // Use PromptBuilder if no prompt override provided
256
- let prompt;
257
- if (promptOverride) {
258
- prompt = promptOverride;
259
- }
260
- else {
261
- // Build enhanced variables for task breakdown
262
- const variables = {
263
- TASK_TITLE: task.title,
264
- TASK_DESCRIPTION: task.description || "No description",
265
- };
266
- // Add full content if available
267
- if (fullContent) {
268
- variables.TASK_CONTENT = fullContent;
269
- }
270
- // Add existing subtasks if available
271
- if (existingSubtasks && existingSubtasks.length > 0) {
272
- const existingSubtasksText = existingSubtasks
273
- .map((subtask, index) => `${index + 1}. ${subtask.title}: ${subtask.description || "No description"}`)
274
- .join("\n");
275
- variables.EXISTING_SUBTASKS = existingSubtasksText;
276
- }
277
- // Add stack info if available
278
- if (stackInfo) {
279
- variables.STACK_INFO = stackInfo;
280
- }
281
- const promptResult = prompt_builder_1.PromptBuilder.buildPrompt({
282
- name: "task-breakdown",
283
- type: "user",
284
- variables,
285
- });
286
- if (!promptResult.success) {
287
- throw new Error(`Failed to build task breakdown prompt: ${promptResult.error}`);
288
- }
289
- prompt = promptResult.prompt;
290
- }
291
- let response;
292
- if (enableFilesystemTools) {
293
- // Use filesystem tools when enabled
294
- const model = this.modelProvider.getModel({
295
- ...this.modelProvider.getAIConfig(),
296
- ...config,
297
- });
298
- const allTools = {
299
- ...filesystem_tools_1.filesystemTools,
300
- };
301
- const result = await (0, ai_1.streamText)({
302
- model,
303
- tools: allTools, // Filesystem tools for project analysis
304
- system: prompts_1.TASK_BREAKDOWN_SYSTEM_PROMPT +
305
- `
306
-
307
- You have access to filesystem tools that allow you to:
308
- - readFile: Read the contents of any file in the project
309
- - listDirectory: List contents of directories
310
-
311
- Use these tools to understand the project structure, existing code, and dependencies when breaking down tasks into subtasks.`,
312
- messages: [{ role: "user", content: userMessage || prompt }],
313
- maxRetries: 0,
314
- onChunk: streamingOptions?.onChunk
315
- ? ({ chunk }) => {
316
- if (chunk.type === "text-delta") {
317
- streamingOptions.onChunk(chunk.text);
318
- }
319
- }
320
- : undefined,
321
- onFinish: streamingOptions?.onFinish
322
- ? ({ text, finishReason, usage }) => {
323
- streamingOptions.onFinish({
324
- text,
325
- finishReason,
326
- usage,
327
- isAborted: false,
328
- });
329
- }
330
- : undefined,
331
- });
332
- response = await result.text;
333
- }
334
- else {
335
- // Use standard streamText without tools
336
- response = await this.streamText("", // empty prompt since we use messages
337
- config, prompts_1.TASK_BREAKDOWN_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 } // Disable retries here since we're handling them at the outer level
338
- );
339
- }
340
- // Parse JSON from response using proper typing
341
- const parseResult = this.jsonParser.parseJSONFromResponse(response);
342
- if (!parseResult.success) {
343
- throw new Error(parseResult.error || "Failed to parse task breakdown response");
344
- }
345
- const parsed = parseResult.data;
346
- // Return plain task data - let storage layer handle IDs and metadata
347
- return (parsed?.subtasks || []).map((subtask) => ({
348
- title: subtask.title,
349
- content: subtask.description || "",
350
- estimatedEffort: subtask.effort,
351
- }));
352
- }, retryConfig, "Task breakdown");
22
+ return this.taskOps.breakdownTask(task, config, promptOverride, userMessage, streamingOptions, retryConfig, fullContent, stackInfo, existingSubtasks, enableFilesystemTools);
353
23
  }
354
24
  async enhanceTask(title, description, config, promptOverride, userMessage, taskId, streamingOptions, retryConfig) {
355
- return this.retryHandler.executeWithRetry(async () => {
356
- let contextInfo = "";
357
- let prdContent = "";
358
- // If taskId is provided, include existing documentation context
359
- if (taskId) {
360
- const contextBuilder = (0, ai_service_factory_1.getContextBuilder)();
361
- try {
362
- const context = await contextBuilder.buildContext(taskId);
363
- if (context.documentation || context.stack || context.prdContent) {
364
- contextInfo = "\n\nAvailable Context:\n";
365
- if (context.stack) {
366
- contextInfo += (0, stack_formatter_1.formatStackForContext)(context.stack) + "\n";
367
- }
368
- if (context.documentation) {
369
- contextInfo += `Documentation Available: ${context.documentation.recap}\n`;
370
- if (context.documentation.files.length > 0) {
371
- contextInfo += `Documentation Files: ${context.documentation.files
372
- .map((f) => f.path)
373
- .join(", ")}\n`;
374
- }
375
- }
376
- if (context.prdContent) {
377
- prdContent = context.prdContent;
378
- }
379
- }
380
- }
381
- catch (error) {
382
- throw error;
383
- }
384
- }
385
- // Use PromptBuilder if no prompt override provided
386
- let prompt;
387
- if (promptOverride) {
388
- prompt = promptOverride;
389
- }
390
- else {
391
- const promptResult = prompt_builder_1.PromptBuilder.buildPrompt({
392
- name: "task-enhancement",
393
- type: "user",
394
- variables: {
395
- TASK_TITLE: title,
396
- TASK_DESCRIPTION: description || "None",
397
- CONTEXT_INFO: contextInfo,
398
- PRD_CONTENT: prdContent || "No PRD content available",
399
- },
400
- });
401
- if (!promptResult.success) {
402
- throw new Error(`Failed to build task enhancement prompt: ${promptResult.error}`);
403
- }
404
- prompt = promptResult.prompt;
405
- }
406
- return this.streamText("", // empty prompt since we use messages
407
- config, prompts_1.TASK_ENHANCEMENT_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 } // Disable retries here since we're handling them at the outer level
408
- );
409
- }, retryConfig, "Task enhancement");
25
+ return this.taskOps.enhanceTask(title, description, config, promptOverride, userMessage, taskId, streamingOptions, retryConfig);
410
26
  }
411
- async reworkPRD(prdContent, feedback, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory, // Working directory passed from service layer
412
- enableFilesystemTools) {
413
- return this.retryHandler.executeWithRetry(async () => {
414
- // Get stack context for better PRD rework using PromptBuilder
415
- // Pass working directory explicitly to avoid process.cwd() issues
416
- let stackInfo = "";
417
- try {
418
- stackInfo = await prompt_builder_1.PromptBuilder.detectStackInfo(workingDirectory);
419
- if (stackInfo === "Not detected") {
420
- stackInfo = "";
421
- }
422
- }
423
- catch (error) {
424
- // Stack info not available, will use empty string
425
- }
426
- // Use PromptBuilder if no prompt override provided
427
- let prompt;
428
- if (promptOverride) {
429
- prompt = promptOverride;
430
- }
431
- else {
432
- const variables = {
433
- PRD_CONTENT: prdContent,
434
- USER_FEEDBACK: feedback,
435
- };
436
- // Only include stack info if we have it
437
- if (stackInfo) {
438
- variables.STACK_INFO = stackInfo;
439
- }
440
- const promptResult = prompt_builder_1.PromptBuilder.buildPrompt({
441
- name: "prd-rework",
442
- type: "user",
443
- variables,
444
- });
445
- if (!promptResult.success) {
446
- throw new Error(`Failed to build PRD rework prompt: ${promptResult.error}`);
447
- }
448
- prompt = promptResult.prompt;
449
- }
450
- if (enableFilesystemTools) {
451
- // Use filesystem tools when enabled
452
- const model = this.modelProvider.getModel({
453
- ...this.modelProvider.getAIConfig(),
454
- ...config,
455
- });
456
- const allTools = {
457
- ...filesystem_tools_1.filesystemTools,
458
- };
459
- const result = await (0, ai_1.streamText)({
460
- model,
461
- tools: allTools, // Filesystem tools for project analysis
462
- system: prompts_1.PRD_REWORK_SYSTEM_PROMPT +
463
- `
464
-
465
- You have access to filesystem tools that allow you to:
466
- - readFile: Read the contents of any file in the project
467
- - listDirectory: List contents of directories
468
-
469
- Use these tools to understand the current project structure, existing code patterns, and dependencies when reworking the PRD based on feedback.`,
470
- messages: [{ role: "user", content: userMessage || prompt }],
471
- maxRetries: 0,
472
- onChunk: streamingOptions?.onChunk
473
- ? ({ chunk }) => {
474
- if (chunk.type === "text-delta") {
475
- streamingOptions.onChunk(chunk.text);
476
- }
477
- }
478
- : undefined,
479
- onFinish: streamingOptions?.onFinish
480
- ? ({ text, finishReason, usage }) => {
481
- streamingOptions.onFinish({
482
- text,
483
- finishReason,
484
- usage,
485
- isAborted: false,
486
- });
487
- }
488
- : undefined,
489
- });
490
- return await result.text;
491
- }
492
- else {
493
- // Use standard streamText without tools
494
- return this.streamText("", // empty prompt since we use messages
495
- config, prompts_1.PRD_REWORK_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 } // Disable retries here since we're handling them at the outer level
496
- );
497
- }
498
- }, retryConfig, "PRD rework");
27
+ async reworkPRD(prdContent, feedback, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory, enableFilesystemTools) {
28
+ return this.prdOps.reworkPRD(prdContent, feedback, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory, enableFilesystemTools);
499
29
  }
500
30
  async generatePRDQuestions(prdContent, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory, enableFilesystemTools) {
501
- return this.retryHandler.executeWithRetry(async () => {
502
- let stackInfo = "";
503
- try {
504
- stackInfo = await prompt_builder_1.PromptBuilder.detectStackInfo(workingDirectory);
505
- if (stackInfo === "Not detected") {
506
- stackInfo = "";
507
- }
508
- }
509
- catch (error) {
510
- // Stack info not available
511
- }
512
- let prompt;
513
- if (promptOverride) {
514
- prompt = promptOverride;
515
- }
516
- else {
517
- const variables = {
518
- PRD_CONTENT: prdContent,
519
- };
520
- if (stackInfo) {
521
- variables.STACK_INFO = stackInfo;
522
- }
523
- const promptResult = prompt_builder_1.PromptBuilder.buildPrompt({
524
- name: "prd-question",
525
- type: "user",
526
- variables,
527
- });
528
- if (!promptResult.success) {
529
- throw new Error(`Failed to build PRD question prompt: ${promptResult.error}`);
530
- }
531
- prompt = promptResult.prompt;
532
- }
533
- // Use PRD_QUESTION_SYSTEM_PROMPT import
534
- const { PRD_QUESTION_SYSTEM_PROMPT } = await Promise.resolve().then(() => __importStar(require("../../prompts")));
535
- let response;
536
- if (enableFilesystemTools) {
537
- const model = this.modelProvider.getModel({
538
- ...this.modelProvider.getAIConfig(),
539
- ...config,
540
- });
541
- const allTools = { ...filesystem_tools_1.filesystemTools };
542
- const result = await (0, ai_1.streamText)({
543
- model,
544
- tools: allTools,
545
- system: PRD_QUESTION_SYSTEM_PROMPT +
546
- `\n\nYou have access to filesystem tools to check existing code/structure if needed.`,
547
- messages: [{ role: "user", content: userMessage || prompt }],
548
- maxRetries: 0,
549
- onChunk: streamingOptions?.onChunk
550
- ? ({ chunk }) => {
551
- if (chunk.type === "text-delta") {
552
- streamingOptions.onChunk(chunk.text);
553
- }
554
- }
555
- : undefined,
556
- onFinish: streamingOptions?.onFinish
557
- ? ({ text, finishReason, usage }) => {
558
- streamingOptions.onFinish({
559
- text,
560
- finishReason,
561
- usage,
562
- isAborted: false,
563
- });
564
- }
565
- : undefined,
566
- });
567
- response = await result.text;
568
- }
569
- else {
570
- response = await this.streamText("", config, PRD_QUESTION_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 });
571
- }
572
- const parseResult = this.jsonParser.parseJSONFromResponse(response);
573
- if (!parseResult.success) {
574
- throw new Error(parseResult.error || "Failed to parse PRD questions");
575
- }
576
- return parseResult.data?.questions || [];
577
- }, retryConfig, "PRD questioning");
31
+ return this.prdOps.generatePRDQuestions(prdContent, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory, enableFilesystemTools);
578
32
  }
579
33
  async answerPRDQuestions(prdContent, questions, config, contextInfo, streamingOptions, retryConfig) {
580
- return this.retryHandler.executeWithRetry(async () => {
581
- // Build prompt for answering questions
582
- const questionsText = questions
583
- .map((q, i) => `${i + 1}. ${q}`)
584
- .join("\n");
585
- const contextText = contextInfo
586
- ? `\n\nProject Context:\n${contextInfo.stackInfo
587
- ? `Technology Stack: ${contextInfo.stackInfo}\n`
588
- : ""}${contextInfo.projectDescription
589
- ? `Project Description: ${contextInfo.projectDescription}\n`
590
- : ""}`
591
- : "";
592
- const prompt = `You are a product expert helping to clarify a PRD.
593
-
594
- PRD Content:
595
- ${prdContent}${contextText}
596
-
597
- Please answer the following questions based on the PRD and context:
598
-
599
- ${questionsText}
600
-
601
- Provide thoughtful, specific answers that will help refine the PRD.
602
- Format your response as JSON with the following structure:
603
- {
604
- "answers": {
605
- "1": "answer to question 1",
606
- "2": "answer to question 2",
607
- ...
608
- }
609
- }`;
610
- const systemPrompt = `You are a product expert analyzing PRDs and answering clarifying questions.
611
- Your answers should be:
612
- - Specific and actionable
613
- - Based on the PRD content and project context
614
- - Helpful for refining the PRD
615
- - Formatted as JSON`;
616
- const response = await this.streamText("", config, systemPrompt, prompt, streamingOptions, { maxAttempts: 1 });
617
- // Parse JSON response
618
- const parseResult = this.jsonParser.parseJSONFromResponse(response);
619
- if (!parseResult.success) {
620
- throw new Error(parseResult.error || "Failed to parse PRD answers response");
621
- }
622
- // Convert numbered keys to question text keys
623
- const answers = {};
624
- const numberedAnswers = parseResult.data?.answers || {};
625
- questions.forEach((question, index) => {
626
- const key = String(index + 1);
627
- if (numberedAnswers[key]) {
628
- answers[question] = numberedAnswers[key];
629
- }
630
- });
631
- return answers;
632
- }, retryConfig, "PRD question answering");
34
+ return this.prdOps.answerPRDQuestions(prdContent, questions, config, contextInfo, streamingOptions, retryConfig);
35
+ }
36
+ async generatePRD(description, config, promptOverride, userMessage, streamingOptions, retryConfig) {
37
+ return this.prdOps.generatePRD(description, config, promptOverride, userMessage, streamingOptions, retryConfig);
38
+ }
39
+ async combinePRDs(prds, originalDescription, config, promptOverride, userMessage, streamingOptions, retryConfig) {
40
+ return this.prdOps.combinePRDs(prds, originalDescription, config, promptOverride, userMessage, streamingOptions, retryConfig);
633
41
  }
634
- // Context7 Integration Methods
635
- async enhanceTaskWithDocumentation(taskId, taskTitle, taskDescription, stackInfo, streamingOptions, retryConfig, config, existingResearch
636
- // existingResearch?: (TaskDocumentation | undefined)[],
637
- ) {
638
- return this.retryHandler
639
- .executeWithRetry(async () => {
640
- // Context7 integration via HTTP calls
641
- const mcpTools = await this.context7Client.getMCPTools();
642
- const defaultAIConfig = this.modelProvider.getAIConfig();
643
- const aiConfig = config
644
- ? { ...defaultAIConfig, ...config }
645
- : defaultAIConfig;
646
- const model = this.modelProvider.getModel(aiConfig);
647
- // Get custom research tools
648
- // const customResearchTools = this.researchTools.getResearchTools();
649
- // Build context for this operation using the actual task ID
650
- const contextBuilder = (0, ai_service_factory_1.getContextBuilder)();
651
- const builtContext = await contextBuilder.buildContext("1.1");
652
- // Build existing research context
653
- const existingResearchContext = existingResearch
654
- ? Object.entries(existingResearch)
655
- .map(([lib, entries]) => `### ${lib}\n${entries
656
- .map((e) => `- Query: "${e.query}"`)
657
- .join("\n")}`)
658
- .join("\n\n")
659
- : "No existing research available.";
660
- // const existingResearchContext = existingResearch
661
- // ? "## Existing research\n" +
662
- // existingResearch
663
- // .map(
664
- // (rs) =>
665
- // rs &&
666
- // `${rs.recap}\n#### librairies\n${rs.libraries.join(`- \n`)}\n\n#### files:\n${rs.libraries.join(`- \n`)}`,
667
- // )
668
- // .join("\n\n")
669
- // : "No existing research available.";
670
- // Use PromptBuilder for consistent prompt handling
671
- const promptResult = prompt_builder_1.PromptBuilder.buildPrompt({
672
- name: "task-enhancement",
673
- type: "user",
674
- variables: {
675
- TASK_TITLE: taskTitle,
676
- TASK_DESCRIPTION: taskDescription,
677
- CONTEXT_INFO: `Technology stack: ${stackInfo || "Not specified"}`,
678
- EXISTING_RESEARCH: existingResearchContext,
679
- PRD_CONTENT: builtContext.prdContent || "No PRD content available",
680
- },
681
- });
682
- if (!promptResult.success) {
683
- throw new Error(`Failed to build task enhancement prompt: ${promptResult.error}`);
684
- }
685
- const prompt = promptResult.prompt;
686
- // Merge Context7 MCP tools with filesystem tools
687
- const allTools = {
688
- ...mcpTools,
689
- ...filesystem_tools_1.filesystemTools,
690
- };
691
- const result = await (0, ai_1.streamText)({
692
- model,
693
- tools: allTools, // Context7 MCP tools + filesystem tools
694
- system: prompts_1.TASK_ENHANCEMENT_SYSTEM_PROMPT +
695
- `
696
-
697
- You have access to Context7 documentation tools and filesystem tools.
698
-
699
- ## Available Tools:
700
- - Context7 MCP tools (context7_resolve_library_id, context7_get_library_docs) for library documentation
701
- - readFile: Read the contents of any file in the project
702
- - listDirectory: List contents of directories
703
-
704
- ## Research Strategy:
705
- 1. Use Context7 MCP tools for library documentation research
706
- 2. Use filesystem tools to understand project structure, existing code, and dependencies
707
- 3. Synthesize information from all sources to enhance the task
708
-
709
- Technology stack context: ${stackInfo || "Not specified"}
710
-
711
- ## Available Cached Research:
712
- ${existingResearchContext}`,
713
- messages: [
714
- {
715
- role: "user",
716
- content: prompt,
717
- },
718
- ],
719
- maxRetries: 0, // Disable built-in retries since we handle them manually
720
- stopWhen: (0, ai_1.stepCountIs)(8), // Allow more steps for comprehensive research
721
- onError: ({ error }) => {
722
- // Call user's error callback if provided
723
- streamingOptions?.onError?.(error);
724
- // Re-throw errors to maintain existing error handling behavior
725
- throw error;
726
- },
727
- onChunk: streamingOptions?.onChunk
728
- ? ({ chunk }) => {
729
- if (chunk.type === "text-delta") {
730
- streamingOptions.onChunk(chunk.text);
731
- }
732
- }
733
- : undefined,
734
- onFinish: streamingOptions?.onFinish
735
- ? ({ text, finishReason, usage }) => {
736
- streamingOptions.onFinish({
737
- text,
738
- finishReason,
739
- usage,
740
- isAborted: false,
741
- });
742
- }
743
- : undefined,
744
- });
745
- // Process tool calls and results properly
746
- const toolCalls = await result.toolCalls;
747
- const toolResults = await result.toolResults;
748
- // Log tool interactions for debugging
749
- if (toolCalls.length > 0) {
750
- console.log("AI made tool calls:", toolCalls.map((tc) => ({ tool: tc.toolName, input: tc.input })));
751
- }
752
- if (toolResults.length > 0) {
753
- console.log("Tool results received:", toolResults.map((tr) => ({
754
- tool: tr.toolName,
755
- output: tr.output,
756
- })));
757
- }
758
- // Process the stream properly to ensure tool calls execute
759
- let fullText = "";
760
- for await (const textPart of result.textStream) {
761
- fullText += textPart;
762
- if (streamingOptions?.onChunk) {
763
- streamingOptions.onChunk(textPart);
764
- }
765
- }
766
- return fullText;
767
- }, retryConfig, "Task enhancement with documentation")
768
- .finally(async () => {
769
- await this.context7Client.closeMCPConnection();
770
- });
42
+ // Documentation Operations - Delegated to DocumentationOperations
43
+ async enhanceTaskWithDocumentation(taskId, taskTitle, taskDescription, stackInfo, streamingOptions, retryConfig, config, existingResearch) {
44
+ return this.docOps.enhanceTaskWithDocumentation(taskId, taskTitle, taskDescription, stackInfo, streamingOptions, retryConfig, config, existingResearch);
771
45
  }
772
46
  async analyzeDocumentationNeeds(taskId, taskTitle, taskDescription, stackInfo, streamingOptions, retryConfig, config, existingResearch) {
773
- return this.retryHandler
774
- .executeWithRetry(async () => {
775
- const mcpTools = await this.context7Client.getMCPTools();
776
- const defaultAIConfig = this.modelProvider.getAIConfig();
777
- const aiConfig = config
778
- ? { ...defaultAIConfig, ...config }
779
- : defaultAIConfig;
780
- const model = this.modelProvider.getModel(aiConfig);
781
- // Build existing research context
782
- const existingResearchContext = existingResearch
783
- ? "## Existing research\n" +
784
- existingResearch
785
- .map((rs) => rs &&
786
- `${rs.recap}\n#### librairies\n${rs.libraries.join(`- \n`)}\n\n#### files:\n${rs.libraries.join(`- \n`)}`)
787
- .join("\n\n")
788
- : "No existing research available.";
789
- // Use PromptBuilder for consistent prompt handling
790
- const promptResult = prompt_builder_1.PromptBuilder.buildPrompt({
791
- name: "documentation-detection",
792
- type: "user",
793
- variables: {
794
- TASK_TITLE: taskTitle,
795
- TASK_DESCRIPTION: taskDescription,
796
- STACK_INFO: stackInfo || "Not specified",
797
- EXISTING_RESEARCH: existingResearchContext,
798
- },
799
- });
800
- if (!promptResult.success) {
801
- throw new Error(`Failed to build documentation detection prompt: ${promptResult.error}`);
802
- }
803
- const prompt = promptResult.prompt;
804
- // Track actual libraries and files saved
805
- const libraries = [];
806
- const files = [];
807
- // Merge Context7 MCP tools with custom research tools
808
- const allTools = {
809
- ...mcpTools,
810
- };
811
- const result = await (0, ai_1.streamText)({
812
- model,
813
- tools: allTools,
814
- system: `You are an expert developer.\nYou have access to Context7 MCP tools for documentation research.\nFetch documentation relevant to the task in the project context and create a document giving that knowledge to the AI assistant that will implement the task.`,
815
- messages: [{ role: "user", content: prompt }],
816
- maxRetries: 0,
817
- stopWhen: (0, ai_1.stepCountIs)(8), // Allow more steps for comprehensive analysis
818
- onError: ({ error }) => {
819
- // Call user's error callback if provided
820
- streamingOptions?.onError?.(error);
821
- // Re-throw errors to maintain existing error handling behavior
822
- throw error;
823
- },
824
- onChunk: streamingOptions?.onChunk
825
- ? ({ chunk }) => {
826
- if (chunk.type === "text-delta") {
827
- streamingOptions.onChunk(chunk.text);
828
- }
829
- else if (chunk.type === "tool-result") {
830
- // Save Context7 documentation if this is a library docs result
831
- if (chunk.toolName === "get-library-docs" && chunk.output) {
832
- (async () => {
833
- try {
834
- // Extract library from the tool input
835
- const input = chunk.input;
836
- const libraryId = input.context7CompatibleLibraryID;
837
- // Generate unique filename using library ID and timestamp
838
- const libraryName = libraryId.split("/").pop() || "unknown";
839
- const timestamp = Date.now();
840
- const filename = input.topic ?? `${libraryName}-${timestamp}`;
841
- // Extract content from tool result object
842
- let content = "";
843
- if (chunk.output &&
844
- typeof chunk.output === "object") {
845
- if ("content" in chunk.output) {
846
- const contentArray = chunk.output
847
- .content;
848
- if (Array.isArray(contentArray)) {
849
- content = contentArray
850
- .map((item) => item.text || "")
851
- .join("\n");
852
- }
853
- else {
854
- content = String(contentArray);
855
- }
856
- }
857
- else if ("text" in chunk.output) {
858
- content = chunk.output.text;
859
- }
860
- }
861
- else if (typeof chunk.output === "string") {
862
- content = chunk.output;
863
- }
864
- if (content) {
865
- // Save documentation and get the file path
866
- const docFile = await this.context7Client.saveContext7Documentation(libraryName, filename, content);
867
- // BUILD THE LIBRARIES ARRAY WITH ACTUAL DATA
868
- libraries.push({
869
- name: libraryName,
870
- context7Id: libraryId,
871
- reason: "Documentation fetched for task implementation",
872
- searchQuery: filename,
873
- });
874
- // TRACK THE ACTUAL FILE PATH
875
- files.push(docFile);
876
- }
877
- }
878
- catch (error) {
879
- console.error("Failed to save Context7 documentation:", error);
880
- }
881
- })();
882
- }
883
- }
884
- }
885
- : undefined,
886
- onFinish: streamingOptions?.onFinish
887
- ? ({ text, finishReason, usage }) => {
888
- streamingOptions.onFinish({
889
- text,
890
- finishReason,
891
- usage,
892
- isAborted: false,
893
- });
894
- }
895
- : undefined,
896
- });
897
- // Process the stream properly to ensure tool calls execute
898
- let fullText = "";
899
- for await (const textPart of result.textStream) {
900
- fullText += textPart;
901
- }
902
- // Get tool results for processing
903
- const toolResults = await result.toolResults;
904
- const toolCalls = await result.toolCalls;
905
- // Save the generated documentation to a task-specific file
906
- if (fullText.trim()) {
907
- try {
908
- const storage = (0, ai_service_factory_1.getStorage)();
909
- const taskDocFile = await storage.saveTaskDocumentation(taskId, fullText);
910
- files.push(taskDocFile);
911
- }
912
- catch (error) {
913
- console.error("Failed to save task documentation:", error);
914
- }
915
- }
916
- return {
917
- libraries,
918
- confidence: libraries.length > 0 ? 0.8 : 0.3,
919
- toolResults: toolResults.map((tr) => ({
920
- toolName: tr.toolName,
921
- output: tr.output,
922
- })),
923
- files, // Return actual files saved
924
- };
925
- }, retryConfig, "Documentation needs analysis")
926
- .finally(async () => {
927
- await this.context7Client.closeMCPConnection();
928
- });
47
+ return this.docOps.analyzeDocumentationNeeds(taskId, taskTitle, taskDescription, stackInfo, streamingOptions, retryConfig, config, existingResearch);
929
48
  }
930
49
  async generateDocumentationRecap(libraries, documentContents, streamingOptions, retryConfig) {
931
- const prompt = `Create a concise recap of the documentation fetched for these libraries:
932
-
933
- Libraries:
934
- ${libraries
935
- .map((lib) => `- ${lib.name} (${lib.context7Id}): ${lib.reason}`)
936
- .join("\n")}
937
-
938
- Documentation Contents:
939
- ${documentContents
940
- .map((doc) => `## ${doc.library}\n${doc.content.substring(0, 500)}...`)
941
- .join("\n\n")}
942
-
943
- Please provide a 2-3 sentence summary of what documentation is available and how it relates to the task.`;
944
- return this.retryHandler.executeWithRetry(async () => {
945
- return this.streamText(prompt, undefined, "You are a technical writer who creates concise summaries of documentation collections.", undefined, streamingOptions, { maxAttempts: 1 } // Disable retries here since we're handling them at the outer level
946
- );
947
- }, retryConfig, "Documentation recap generation");
50
+ return this.docOps.generateDocumentationRecap(libraries, documentContents, streamingOptions, retryConfig);
948
51
  }
949
52
  async planTask(taskContext, taskDetails, config, promptOverride, userMessage, streamingOptions, retryConfig) {
950
- return this.retryHandler.executeWithRetry(async () => {
951
- // Use PromptBuilder if no prompt override provided
952
- let prompt;
953
- if (promptOverride) {
954
- prompt = promptOverride;
955
- }
956
- else {
957
- const promptResult = prompt_builder_1.PromptBuilder.buildPrompt({
958
- name: "task-planning",
959
- type: "user",
960
- variables: {
961
- TASK_CONTEXT: taskContext,
962
- TASK_DETAILS: taskDetails,
963
- },
964
- });
965
- if (!promptResult.success) {
966
- throw new Error(`Failed to build task planning prompt: ${promptResult.error}`);
967
- }
968
- prompt = promptResult.prompt;
969
- }
970
- const model = this.modelProvider.getModel({
971
- ...this.modelProvider.getAIConfig(),
972
- ...config,
973
- });
974
- // Get MCP tools and merge with filesystem tools
975
- const mcpTools = await this.context7Client.getMCPTools();
976
- const allTools = {
977
- ...mcpTools,
978
- ...filesystem_tools_1.filesystemTools,
979
- };
980
- const result = (0, ai_1.streamText)({
981
- model,
982
- tools: allTools, // Context7 MCP tools + filesystem tools
983
- system: prompts_1.TASK_PLANNING_SYSTEM_PROMPT +
984
- `
985
-
986
- You have access to filesystem tools that allow you to:
987
- - readFile: Read the contents of any file in the project
988
- - listDirectory: List contents of directories
989
-
990
- Use these tools to understand the project structure, existing code, and dependencies when creating implementation plans.`,
991
- messages: [{ role: "user", content: userMessage || prompt }],
992
- maxRetries: 0,
993
- onChunk: streamingOptions?.onChunk
994
- ? ({ chunk }) => {
995
- if (chunk.type === "text-delta") {
996
- streamingOptions.onChunk(chunk.text);
997
- }
998
- }
999
- : undefined,
1000
- onFinish: streamingOptions?.onFinish
1001
- ? ({ text, finishReason, usage }) => {
1002
- streamingOptions.onFinish({
1003
- text,
1004
- finishReason,
1005
- usage,
1006
- isAborted: false,
1007
- });
1008
- }
1009
- : undefined,
1010
- });
1011
- // Return the plan text directly - no JSON parsing needed
1012
- return (await result).text;
1013
- }, retryConfig, "Task planning");
53
+ return this.taskOps.planTask(taskContext, taskDetails, config, promptOverride, userMessage, streamingOptions, retryConfig);
1014
54
  }
1015
55
  }
1016
56
  exports.AIOperations = AIOperations;