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.
Files changed (129) hide show
  1. package/README.md +96 -40
  2. package/dist/commands/prd.js +4 -0
  3. package/dist/commands/prompt.d.ts.map +1 -1
  4. package/dist/commands/prompt.js +69 -61
  5. package/dist/commands/tasks/create.d.ts +3 -0
  6. package/dist/commands/tasks/create.d.ts.map +1 -0
  7. package/dist/commands/tasks/create.js +58 -0
  8. package/dist/commands/tasks/delete.d.ts +3 -0
  9. package/dist/commands/tasks/delete.d.ts.map +1 -0
  10. package/dist/commands/tasks/delete.js +40 -0
  11. package/dist/commands/tasks/document.d.ts +5 -0
  12. package/dist/commands/tasks/document.d.ts.map +1 -0
  13. package/dist/commands/tasks/document.js +118 -0
  14. package/dist/commands/tasks/enhance.d.ts +3 -0
  15. package/dist/commands/tasks/enhance.d.ts.map +1 -0
  16. package/dist/commands/tasks/enhance.js +86 -0
  17. package/dist/commands/tasks/execute.d.ts +3 -0
  18. package/dist/commands/tasks/execute.d.ts.map +1 -0
  19. package/dist/commands/tasks/execute.js +33 -0
  20. package/dist/commands/tasks/index.d.ts +16 -0
  21. package/dist/commands/tasks/index.d.ts.map +1 -0
  22. package/dist/commands/tasks/index.js +31 -0
  23. package/dist/commands/tasks/list.d.ts +3 -0
  24. package/dist/commands/tasks/list.d.ts.map +1 -0
  25. package/dist/commands/tasks/list.js +27 -0
  26. package/dist/commands/tasks/next.d.ts +3 -0
  27. package/dist/commands/tasks/next.d.ts.map +1 -0
  28. package/dist/commands/tasks/next.js +44 -0
  29. package/dist/commands/tasks/plan.d.ts +7 -0
  30. package/dist/commands/tasks/plan.d.ts.map +1 -0
  31. package/dist/commands/tasks/plan.js +131 -0
  32. package/dist/commands/tasks/show.d.ts +3 -0
  33. package/dist/commands/tasks/show.d.ts.map +1 -0
  34. package/dist/commands/tasks/show.js +23 -0
  35. package/dist/commands/tasks/split.d.ts +3 -0
  36. package/dist/commands/tasks/split.d.ts.map +1 -0
  37. package/dist/commands/tasks/split.js +95 -0
  38. package/dist/commands/tasks/status.d.ts +3 -0
  39. package/dist/commands/tasks/status.d.ts.map +1 -0
  40. package/dist/commands/tasks/status.js +26 -0
  41. package/dist/commands/tasks/subtasks.d.ts +3 -0
  42. package/dist/commands/tasks/subtasks.d.ts.map +1 -0
  43. package/dist/commands/tasks/subtasks.js +35 -0
  44. package/dist/commands/tasks/tags.d.ts +4 -0
  45. package/dist/commands/tasks/tags.d.ts.map +1 -0
  46. package/dist/commands/tasks/tags.js +37 -0
  47. package/dist/commands/tasks/tree.d.ts +3 -0
  48. package/dist/commands/tasks/tree.d.ts.map +1 -0
  49. package/dist/commands/tasks/tree.js +20 -0
  50. package/dist/commands/tasks/update.d.ts +3 -0
  51. package/dist/commands/tasks/update.d.ts.map +1 -0
  52. package/dist/commands/tasks/update.js +35 -0
  53. package/dist/commands/tasks.d.ts.map +1 -1
  54. package/dist/commands/tasks.js +23 -594
  55. package/dist/commands/workflow.d.ts +4 -0
  56. package/dist/commands/workflow.d.ts.map +1 -0
  57. package/dist/commands/workflow.js +434 -0
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +3 -1
  60. package/dist/lib/ai-service/ai-operations.d.ts +5 -3
  61. package/dist/lib/ai-service/ai-operations.d.ts.map +1 -1
  62. package/dist/lib/ai-service/ai-operations.js +231 -30
  63. package/dist/lib/ai-service/filesystem-tools.d.ts +69 -0
  64. package/dist/lib/ai-service/filesystem-tools.d.ts.map +1 -0
  65. package/dist/lib/ai-service/filesystem-tools.js +70 -0
  66. package/dist/lib/ai-service/research-tools.d.ts.map +1 -1
  67. package/dist/lib/ai-service/research-tools.js +2 -2
  68. package/dist/lib/context-builder.d.ts +2 -1
  69. package/dist/lib/context-builder.d.ts.map +1 -1
  70. package/dist/lib/context-builder.js +3 -8
  71. package/dist/lib/executors/claude-code-executor.d.ts +6 -0
  72. package/dist/lib/executors/claude-code-executor.d.ts.map +1 -0
  73. package/dist/lib/executors/claude-code-executor.js +41 -0
  74. package/dist/lib/executors/codex-executor.d.ts +6 -0
  75. package/dist/lib/executors/codex-executor.d.ts.map +1 -0
  76. package/dist/lib/executors/codex-executor.js +41 -0
  77. package/dist/lib/executors/executor-factory.d.ts.map +1 -1
  78. package/dist/lib/executors/executor-factory.js +6 -3
  79. package/dist/lib/executors/gemini-executor.d.ts +6 -0
  80. package/dist/lib/executors/gemini-executor.d.ts.map +1 -0
  81. package/dist/lib/executors/gemini-executor.js +41 -0
  82. package/dist/lib/executors/opencode-executor.d.ts.map +1 -1
  83. package/dist/lib/executors/opencode-executor.js +2 -3
  84. package/dist/lib/hooks/logger.d.ts +2 -0
  85. package/dist/lib/hooks/logger.d.ts.map +1 -0
  86. package/dist/lib/hooks/logger.js +27 -0
  87. package/dist/lib/hooks.d.ts +64 -0
  88. package/dist/lib/hooks.d.ts.map +1 -0
  89. package/dist/lib/hooks.js +60 -0
  90. package/dist/lib/index.d.ts +18 -17
  91. package/dist/lib/index.d.ts.map +1 -1
  92. package/dist/lib/index.js +3 -3
  93. package/dist/lib/prompt-builder.d.ts +8 -0
  94. package/dist/lib/prompt-builder.d.ts.map +1 -1
  95. package/dist/lib/prompt-builder.js +110 -4
  96. package/dist/lib/{storage.d.ts → storage/file-system.d.ts} +4 -3
  97. package/dist/lib/storage/file-system.d.ts.map +1 -0
  98. package/dist/lib/{storage.js → storage/file-system.js} +141 -152
  99. package/dist/lib/storage/types.d.ts +43 -0
  100. package/dist/lib/storage/types.d.ts.map +1 -0
  101. package/dist/lib/storage/types.js +2 -0
  102. package/dist/lib/task-execution.d.ts.map +1 -1
  103. package/dist/lib/task-execution.js +63 -14
  104. package/dist/prompts/workflow-assistance.d.ts +32 -0
  105. package/dist/prompts/workflow-assistance.d.ts.map +1 -0
  106. package/dist/prompts/workflow-assistance.js +130 -0
  107. package/dist/services/prd.d.ts +2 -0
  108. package/dist/services/prd.d.ts.map +1 -1
  109. package/dist/services/prd.js +4 -4
  110. package/dist/services/tasks.d.ts +13 -6
  111. package/dist/services/tasks.d.ts.map +1 -1
  112. package/dist/services/tasks.js +202 -88
  113. package/dist/services/workflow-ai-assistant.d.ts +74 -0
  114. package/dist/services/workflow-ai-assistant.d.ts.map +1 -0
  115. package/dist/services/workflow-ai-assistant.js +223 -0
  116. package/dist/test/hooks.test.d.ts +2 -0
  117. package/dist/test/hooks.test.d.ts.map +1 -0
  118. package/dist/test/hooks.test.js +58 -0
  119. package/dist/test/storage.test.js +16 -16
  120. package/dist/types/options.d.ts +35 -0
  121. package/dist/types/options.d.ts.map +1 -1
  122. package/dist/utils/ai-service-factory.d.ts +5 -5
  123. package/dist/utils/ai-service-factory.d.ts.map +1 -1
  124. package/dist/utils/ai-service-factory.js +4 -3
  125. package/dist/utils/workflow-prompts.d.ts +17 -0
  126. package/dist/utils/workflow-prompts.d.ts.map +1 -0
  127. package/dist/utils/workflow-prompts.js +88 -0
  128. package/package.json +2 -2
  129. package/dist/lib/storage.d.ts.map +0 -1
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AIOperations = void 0;
4
4
  const ai_1 = require("ai");
5
- const context_builder_1 = require("../context-builder");
6
5
  const prompt_builder_1 = require("../prompt-builder");
7
6
  const stack_formatter_1 = require("../../utils/stack-formatter");
8
7
  const prompts_1 = require("../../prompts");
@@ -11,6 +10,7 @@ const json_parser_1 = require("./json-parser");
11
10
  const mcp_client_1 = require("./mcp-client");
12
11
  const retry_handler_1 = require("./retry-handler");
13
12
  const model_provider_1 = require("./model-provider");
13
+ const filesystem_tools_1 = require("./filesystem-tools");
14
14
  class AIOperations {
15
15
  jsonParser = new json_parser_1.JSONParser();
16
16
  context7Client = new mcp_client_1.Context7Client();
@@ -81,7 +81,8 @@ class AIOperations {
81
81
  return fullText;
82
82
  }, retryConfig, "AI streaming");
83
83
  }
84
- async parsePRD(prdContent, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory) {
84
+ async parsePRD(prdContent, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory, // Working directory passed from service layer
85
+ enableFilesystemTools) {
85
86
  return this.retryHandler.executeWithRetry(async () => {
86
87
  // Get stack context for better PRD parsing using PromptBuilder
87
88
  // Pass working directory explicitly to avoid process.cwd() issues
@@ -118,8 +119,57 @@ class AIOperations {
118
119
  }
119
120
  enhancedPrompt = promptResult.prompt; // TypeScript: prompt is guaranteed when success is true
120
121
  }
121
- const response = await this.streamText("", // empty prompt since we use messages
122
- config, prompts_1.PRD_PARSING_SYSTEM_PROMPT, userMessage || enhancedPrompt, streamingOptions, { maxAttempts: 1 });
122
+ let response;
123
+ if (enableFilesystemTools) {
124
+ // Use filesystem tools when enabled
125
+ const model = this.modelProvider.getModel({
126
+ ...this.modelProvider.getAIConfig(),
127
+ ...config,
128
+ });
129
+ const allTools = {
130
+ ...filesystem_tools_1.filesystemTools,
131
+ };
132
+ const result = await (0, ai_1.streamText)({
133
+ model,
134
+ tools: allTools, // Filesystem tools for project analysis
135
+ system: prompts_1.PRD_PARSING_SYSTEM_PROMPT +
136
+ `
137
+
138
+ You have access to filesystem tools that allow you to:
139
+ - readFile: Read the contents of any file in the project
140
+ - listDirectory: List contents of directories
141
+
142
+ Use these tools to understand the project structure, existing code patterns, and dependencies when parsing the PRD and creating tasks.`,
143
+ messages: [
144
+ { role: "user", content: userMessage || enhancedPrompt },
145
+ ],
146
+ maxRetries: 0,
147
+ onChunk: streamingOptions?.onChunk
148
+ ? ({ chunk }) => {
149
+ if (chunk.type === "text-delta") {
150
+ streamingOptions.onChunk(chunk.text);
151
+ }
152
+ }
153
+ : undefined,
154
+ onFinish: streamingOptions?.onFinish
155
+ ? ({ text, finishReason, usage }) => {
156
+ streamingOptions.onFinish({
157
+ text,
158
+ finishReason,
159
+ usage,
160
+ isAborted: false,
161
+ });
162
+ }
163
+ : undefined,
164
+ });
165
+ response = await result.text;
166
+ }
167
+ else {
168
+ // Use standard streamText without tools
169
+ response = await this.streamText("", // empty prompt since we use messages
170
+ config, prompts_1.PRD_PARSING_SYSTEM_PROMPT, userMessage || enhancedPrompt, streamingOptions, { maxAttempts: 1 } // Disable retries here since we're handling them at the outer level
171
+ );
172
+ }
123
173
  // Parse JSON from response using proper typing
124
174
  const parseResult = this.jsonParser.parseJSONFromResponse(response);
125
175
  if (!parseResult.success) {
@@ -167,7 +217,7 @@ class AIOperations {
167
217
  };
168
218
  }, retryConfig, "PRD parsing");
169
219
  }
170
- async breakdownTask(task, config, promptOverride, userMessage, streamingOptions, retryConfig, fullContent, stackInfo, existingSubtasks) {
220
+ async breakdownTask(task, config, promptOverride, userMessage, streamingOptions, retryConfig, fullContent, stackInfo, existingSubtasks, enableFilesystemTools) {
171
221
  return this.retryHandler.executeWithRetry(async () => {
172
222
  // Use PromptBuilder if no prompt override provided
173
223
  let prompt;
@@ -205,8 +255,55 @@ class AIOperations {
205
255
  }
206
256
  prompt = promptResult.prompt;
207
257
  }
208
- const response = await this.streamText("", // empty prompt since we use messages
209
- config, prompts_1.TASK_BREAKDOWN_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 });
258
+ let response;
259
+ if (enableFilesystemTools) {
260
+ // Use filesystem tools when enabled
261
+ const model = this.modelProvider.getModel({
262
+ ...this.modelProvider.getAIConfig(),
263
+ ...config,
264
+ });
265
+ const allTools = {
266
+ ...filesystem_tools_1.filesystemTools,
267
+ };
268
+ const result = await (0, ai_1.streamText)({
269
+ model,
270
+ tools: allTools, // Filesystem tools for project analysis
271
+ system: prompts_1.TASK_BREAKDOWN_SYSTEM_PROMPT +
272
+ `
273
+
274
+ You have access to filesystem tools that allow you to:
275
+ - readFile: Read the contents of any file in the project
276
+ - listDirectory: List contents of directories
277
+
278
+ Use these tools to understand the project structure, existing code, and dependencies when breaking down tasks into subtasks.`,
279
+ messages: [{ role: "user", content: userMessage || prompt }],
280
+ maxRetries: 0,
281
+ onChunk: streamingOptions?.onChunk
282
+ ? ({ chunk }) => {
283
+ if (chunk.type === "text-delta") {
284
+ streamingOptions.onChunk(chunk.text);
285
+ }
286
+ }
287
+ : undefined,
288
+ onFinish: streamingOptions?.onFinish
289
+ ? ({ text, finishReason, usage }) => {
290
+ streamingOptions.onFinish({
291
+ text,
292
+ finishReason,
293
+ usage,
294
+ isAborted: false,
295
+ });
296
+ }
297
+ : undefined,
298
+ });
299
+ response = await result.text;
300
+ }
301
+ else {
302
+ // Use standard streamText without tools
303
+ response = await this.streamText("", // empty prompt since we use messages
304
+ config, prompts_1.TASK_BREAKDOWN_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 } // Disable retries here since we're handling them at the outer level
305
+ );
306
+ }
210
307
  // Parse JSON from response using proper typing
211
308
  const parseResult = this.jsonParser.parseJSONFromResponse(response);
212
309
  if (!parseResult.success) {
@@ -227,7 +324,7 @@ class AIOperations {
227
324
  let prdContent = "";
228
325
  // If taskId is provided, include existing documentation context
229
326
  if (taskId) {
230
- const contextBuilder = new context_builder_1.ContextBuilder();
327
+ const contextBuilder = (0, ai_service_factory_1.getContextBuilder)();
231
328
  try {
232
329
  const context = await contextBuilder.buildContext(taskId);
233
330
  if (context.documentation || context.stack || context.prdContent) {
@@ -238,7 +335,9 @@ class AIOperations {
238
335
  if (context.documentation) {
239
336
  contextInfo += `Documentation Available: ${context.documentation.recap}\n`;
240
337
  if (context.documentation.files.length > 0) {
241
- contextInfo += `Documentation Files: ${context.documentation.files.map((f) => f.path).join(", ")}\n`;
338
+ contextInfo += `Documentation Files: ${context.documentation.files
339
+ .map((f) => f.path)
340
+ .join(", ")}\n`;
242
341
  }
243
342
  }
244
343
  if (context.prdContent) {
@@ -272,10 +371,12 @@ class AIOperations {
272
371
  prompt = promptResult.prompt;
273
372
  }
274
373
  return this.streamText("", // empty prompt since we use messages
275
- config, prompts_1.TASK_ENHANCEMENT_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 });
374
+ config, prompts_1.TASK_ENHANCEMENT_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 } // Disable retries here since we're handling them at the outer level
375
+ );
276
376
  }, retryConfig, "Task enhancement");
277
377
  }
278
- async reworkPRD(prdContent, feedback, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory) {
378
+ async reworkPRD(prdContent, feedback, config, promptOverride, userMessage, streamingOptions, retryConfig, workingDirectory, // Working directory passed from service layer
379
+ enableFilesystemTools) {
279
380
  return this.retryHandler.executeWithRetry(async () => {
280
381
  // Get stack context for better PRD rework using PromptBuilder
281
382
  // Pass working directory explicitly to avoid process.cwd() issues
@@ -313,12 +414,60 @@ class AIOperations {
313
414
  }
314
415
  prompt = promptResult.prompt;
315
416
  }
316
- return this.streamText("", // empty prompt since we use messages
317
- config, prompts_1.PRD_REWORK_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 });
417
+ if (enableFilesystemTools) {
418
+ // Use filesystem tools when enabled
419
+ const model = this.modelProvider.getModel({
420
+ ...this.modelProvider.getAIConfig(),
421
+ ...config,
422
+ });
423
+ const allTools = {
424
+ ...filesystem_tools_1.filesystemTools,
425
+ };
426
+ const result = await (0, ai_1.streamText)({
427
+ model,
428
+ tools: allTools, // Filesystem tools for project analysis
429
+ system: prompts_1.PRD_REWORK_SYSTEM_PROMPT +
430
+ `
431
+
432
+ You have access to filesystem tools that allow you to:
433
+ - readFile: Read the contents of any file in the project
434
+ - listDirectory: List contents of directories
435
+
436
+ Use these tools to understand the current project structure, existing code patterns, and dependencies when reworking the PRD based on feedback.`,
437
+ messages: [{ role: "user", content: userMessage || prompt }],
438
+ maxRetries: 0,
439
+ onChunk: streamingOptions?.onChunk
440
+ ? ({ chunk }) => {
441
+ if (chunk.type === "text-delta") {
442
+ streamingOptions.onChunk(chunk.text);
443
+ }
444
+ }
445
+ : undefined,
446
+ onFinish: streamingOptions?.onFinish
447
+ ? ({ text, finishReason, usage }) => {
448
+ streamingOptions.onFinish({
449
+ text,
450
+ finishReason,
451
+ usage,
452
+ isAborted: false,
453
+ });
454
+ }
455
+ : undefined,
456
+ });
457
+ return await result.text;
458
+ }
459
+ else {
460
+ // Use standard streamText without tools
461
+ return this.streamText("", // empty prompt since we use messages
462
+ config, prompts_1.PRD_REWORK_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 } // Disable retries here since we're handling them at the outer level
463
+ );
464
+ }
318
465
  }, retryConfig, "PRD rework");
319
466
  }
320
467
  // Context7 Integration Methods
321
- async enhanceTaskWithDocumentation(taskId, taskTitle, taskDescription, stackInfo, streamingOptions, retryConfig, config, existingResearch) {
468
+ async enhanceTaskWithDocumentation(taskId, taskTitle, taskDescription, stackInfo, streamingOptions, retryConfig, config, existingResearch
469
+ // existingResearch?: (TaskDocumentation | undefined)[],
470
+ ) {
322
471
  return this.retryHandler
323
472
  .executeWithRetry(async () => {
324
473
  // Context7 integration via HTTP calls
@@ -331,12 +480,14 @@ class AIOperations {
331
480
  // Get custom research tools
332
481
  // const customResearchTools = this.researchTools.getResearchTools();
333
482
  // Build context for this operation using the actual task ID
334
- const contextBuilder = new context_builder_1.ContextBuilder();
483
+ const contextBuilder = (0, ai_service_factory_1.getContextBuilder)();
335
484
  const builtContext = await contextBuilder.buildContext("1.1");
336
485
  // Build existing research context
337
486
  const existingResearchContext = existingResearch
338
487
  ? Object.entries(existingResearch)
339
- .map(([lib, entries]) => `### ${lib}\n${entries.map((e) => `- Query: "${e.query}"`).join("\n")}`)
488
+ .map(([lib, entries]) => `### ${lib}\n${entries
489
+ .map((e) => `- Query: "${e.query}"`)
490
+ .join("\n")}`)
340
491
  .join("\n\n")
341
492
  : "No existing research available.";
342
493
  // const existingResearchContext = existingResearch
@@ -365,22 +516,28 @@ class AIOperations {
365
516
  throw new Error(`Failed to build task enhancement prompt: ${promptResult.error}`);
366
517
  }
367
518
  const prompt = promptResult.prompt;
368
- // Merge Context7 MCP tools with custom research tools
519
+ // Merge Context7 MCP tools with filesystem tools
369
520
  const allTools = {
370
521
  ...mcpTools,
371
- // ...customResearchTools,
522
+ ...filesystem_tools_1.filesystemTools,
372
523
  };
373
- const result = (0, ai_1.streamText)({
524
+ const result = await (0, ai_1.streamText)({
374
525
  model,
375
- tools: allTools, // Context7 MCP tools + custom research tools
526
+ tools: allTools, // Context7 MCP tools + filesystem tools
376
527
  system: prompts_1.TASK_ENHANCEMENT_SYSTEM_PROMPT +
377
528
  `
378
529
 
379
- You have access to Context7 documentation tools.
530
+ You have access to Context7 documentation tools and filesystem tools.
531
+
532
+ ## Available Tools:
533
+ - Context7 MCP tools (context7_resolve_library_id, context7_get_library_docs) for library documentation
534
+ - readFile: Read the contents of any file in the project
535
+ - listDirectory: List contents of directories
380
536
 
381
537
  ## Research Strategy:
382
- 1. Use Context7 MCP tools (context7_resolve_library_id, context7_get_library_docs) for any new research needed
383
- 2. Synthesize information from all sources to enhance the task
538
+ 1. Use Context7 MCP tools for library documentation research
539
+ 2. Use filesystem tools to understand project structure, existing code, and dependencies
540
+ 3. Synthesize information from all sources to enhance the task
384
541
 
385
542
  Technology stack context: ${stackInfo || "Not specified"}
386
543
 
@@ -484,7 +641,7 @@ ${existingResearchContext}`,
484
641
  const allTools = {
485
642
  ...mcpTools,
486
643
  };
487
- const result = (0, ai_1.streamText)({
644
+ const result = await (0, ai_1.streamText)({
488
645
  model,
489
646
  tools: allTools,
490
647
  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.`,
@@ -607,14 +764,19 @@ ${existingResearchContext}`,
607
764
  const prompt = `Create a concise recap of the documentation fetched for these libraries:
608
765
 
609
766
  Libraries:
610
- ${libraries.map((lib) => `- ${lib.name} (${lib.context7Id}): ${lib.reason}`).join("\n")}
767
+ ${libraries
768
+ .map((lib) => `- ${lib.name} (${lib.context7Id}): ${lib.reason}`)
769
+ .join("\n")}
611
770
 
612
771
  Documentation Contents:
613
- ${documentContents.map((doc) => `## ${doc.library}\n${doc.content.substring(0, 500)}...`).join("\n\n")}
772
+ ${documentContents
773
+ .map((doc) => `## ${doc.library}\n${doc.content.substring(0, 500)}...`)
774
+ .join("\n\n")}
614
775
 
615
776
  Please provide a 2-3 sentence summary of what documentation is available and how it relates to the task.`;
616
777
  return this.retryHandler.executeWithRetry(async () => {
617
- return this.streamText(prompt, undefined, "You are a technical writer who creates concise summaries of documentation collections.", undefined, streamingOptions, { maxAttempts: 1 });
778
+ 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
779
+ );
618
780
  }, retryConfig, "Documentation recap generation");
619
781
  }
620
782
  async planTask(taskContext, taskDetails, config, promptOverride, userMessage, streamingOptions, retryConfig) {
@@ -638,10 +800,49 @@ Please provide a 2-3 sentence summary of what documentation is available and how
638
800
  }
639
801
  prompt = promptResult.prompt;
640
802
  }
641
- const response = await this.streamText("", // empty prompt since we use messages
642
- config, prompts_1.TASK_PLANNING_SYSTEM_PROMPT, userMessage || prompt, streamingOptions, { maxAttempts: 1 });
803
+ const model = this.modelProvider.getModel({
804
+ ...this.modelProvider.getAIConfig(),
805
+ ...config,
806
+ });
807
+ // Get MCP tools and merge with filesystem tools
808
+ const mcpTools = await this.context7Client.getMCPTools();
809
+ const allTools = {
810
+ ...mcpTools,
811
+ ...filesystem_tools_1.filesystemTools,
812
+ };
813
+ const result = (0, ai_1.streamText)({
814
+ model,
815
+ tools: allTools, // Context7 MCP tools + filesystem tools
816
+ system: prompts_1.TASK_PLANNING_SYSTEM_PROMPT +
817
+ `
818
+
819
+ You have access to filesystem tools that allow you to:
820
+ - readFile: Read the contents of any file in the project
821
+ - listDirectory: List contents of directories
822
+
823
+ Use these tools to understand the project structure, existing code, and dependencies when creating implementation plans.`,
824
+ messages: [{ role: "user", content: userMessage || prompt }],
825
+ maxRetries: 0,
826
+ onChunk: streamingOptions?.onChunk
827
+ ? ({ chunk }) => {
828
+ if (chunk.type === "text-delta") {
829
+ streamingOptions.onChunk(chunk.text);
830
+ }
831
+ }
832
+ : undefined,
833
+ onFinish: streamingOptions?.onFinish
834
+ ? ({ text, finishReason, usage }) => {
835
+ streamingOptions.onFinish({
836
+ text,
837
+ finishReason,
838
+ usage,
839
+ isAborted: false,
840
+ });
841
+ }
842
+ : undefined,
843
+ });
643
844
  // Return the plan text directly - no JSON parsing needed
644
- return response;
845
+ return (await result).text;
645
846
  }, retryConfig, "Task planning");
646
847
  }
647
848
  }
@@ -0,0 +1,69 @@
1
+ export declare const readFileTool: import("ai").Tool<{
2
+ filePath: string;
3
+ }, {
4
+ success: boolean;
5
+ content: string;
6
+ path: string;
7
+ size: number;
8
+ error?: undefined;
9
+ } | {
10
+ success: boolean;
11
+ error: string;
12
+ content?: undefined;
13
+ path?: undefined;
14
+ size?: undefined;
15
+ }>;
16
+ export declare const listDirectoryTool: import("ai").Tool<{
17
+ dirPath: string;
18
+ }, {
19
+ success: boolean;
20
+ contents: {
21
+ name: string;
22
+ type: string;
23
+ path: string;
24
+ size: number | undefined;
25
+ }[];
26
+ directory: string;
27
+ error?: undefined;
28
+ } | {
29
+ success: boolean;
30
+ error: string;
31
+ contents: never[];
32
+ directory?: undefined;
33
+ }>;
34
+ export declare const filesystemTools: {
35
+ readFile: import("ai").Tool<{
36
+ filePath: string;
37
+ }, {
38
+ success: boolean;
39
+ content: string;
40
+ path: string;
41
+ size: number;
42
+ error?: undefined;
43
+ } | {
44
+ success: boolean;
45
+ error: string;
46
+ content?: undefined;
47
+ path?: undefined;
48
+ size?: undefined;
49
+ }>;
50
+ listDirectory: import("ai").Tool<{
51
+ dirPath: string;
52
+ }, {
53
+ success: boolean;
54
+ contents: {
55
+ name: string;
56
+ type: string;
57
+ path: string;
58
+ size: number | undefined;
59
+ }[];
60
+ directory: string;
61
+ error?: undefined;
62
+ } | {
63
+ success: boolean;
64
+ error: string;
65
+ contents: never[];
66
+ directory?: undefined;
67
+ }>;
68
+ };
69
+ //# sourceMappingURL=filesystem-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem-tools.d.ts","sourceRoot":"","sources":["../../../src/lib/ai-service/filesystem-tools.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;EAwBvB,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;EAoC5B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAG3B,CAAC"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.filesystemTools = exports.listDirectoryTool = exports.readFileTool = void 0;
4
+ const ai_1 = require("ai");
5
+ const v3_1 = require("zod/v3");
6
+ const promises_1 = require("fs/promises");
7
+ const path_1 = require("path");
8
+ exports.readFileTool = (0, ai_1.tool)({
9
+ description: "Read the contents of a file",
10
+ inputSchema: v3_1.z.object({
11
+ filePath: v3_1.z.string().describe("Path to the file to read"),
12
+ }),
13
+ execute: async ({ filePath }) => {
14
+ try {
15
+ const resolvedPath = (0, path_1.resolve)(filePath);
16
+ const content = await (0, promises_1.readFile)(resolvedPath, 'utf-8');
17
+ const stats = await (0, promises_1.stat)(resolvedPath);
18
+ return {
19
+ success: true,
20
+ content,
21
+ path: (0, path_1.relative)(process.cwd(), resolvedPath),
22
+ size: stats.size,
23
+ };
24
+ }
25
+ catch (error) {
26
+ return {
27
+ success: false,
28
+ error: error instanceof Error ? error.message : "Unknown error",
29
+ };
30
+ }
31
+ },
32
+ });
33
+ exports.listDirectoryTool = (0, ai_1.tool)({
34
+ description: "List contents of a directory",
35
+ inputSchema: v3_1.z.object({
36
+ dirPath: v3_1.z.string().describe("Directory path to list"),
37
+ }),
38
+ execute: async ({ dirPath }) => {
39
+ try {
40
+ const resolvedPath = (0, path_1.resolve)(dirPath);
41
+ const entries = await (0, promises_1.readdir)(resolvedPath, { withFileTypes: true });
42
+ const contents = await Promise.all(entries.map(async (entry) => {
43
+ const fullPath = (0, path_1.join)(resolvedPath, entry.name);
44
+ const stats = await (0, promises_1.stat)(fullPath);
45
+ return {
46
+ name: entry.name,
47
+ type: entry.isDirectory() ? "directory" : "file",
48
+ path: (0, path_1.relative)(process.cwd(), fullPath),
49
+ size: entry.isFile() ? stats.size : undefined,
50
+ };
51
+ }));
52
+ return {
53
+ success: true,
54
+ contents,
55
+ directory: (0, path_1.relative)(process.cwd(), resolvedPath),
56
+ };
57
+ }
58
+ catch (error) {
59
+ return {
60
+ success: false,
61
+ error: error instanceof Error ? error.message : "Unknown error",
62
+ contents: [],
63
+ };
64
+ }
65
+ },
66
+ });
67
+ exports.filesystemTools = {
68
+ readFile: exports.readFileTool,
69
+ listDirectory: exports.listDirectoryTool,
70
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"research-tools.d.ts","sourceRoot":"","sources":["../../../src/lib/ai-service/research-tools.ts"],"names":[],"mappings":"AAIA,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAsB;CAwMtC"}
1
+ {"version":3,"file":"research-tools.d.ts","sourceRoot":"","sources":["../../../src/lib/ai-service/research-tools.ts"],"names":[],"mappings":"AAKA,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAgC;CAwMhD"}
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ResearchTools = void 0;
4
- const storage_1 = require("../storage");
4
+ const ai_service_factory_1 = require("../../utils/ai-service-factory");
5
5
  class ResearchTools {
6
- storage = new storage_1.LocalStorage();
6
+ storage = (0, ai_service_factory_1.getStorage)();
7
7
  }
8
8
  exports.ResearchTools = ResearchTools;
@@ -1,9 +1,10 @@
1
1
  import { TaskContext, TaskDocumentation } from "../types";
2
+ import { TaskRepository } from "./storage/types";
2
3
  export declare class ContextBuilder {
3
4
  private storage;
4
5
  private taskOMatic;
5
6
  private initialized;
6
- constructor();
7
+ constructor(storage: TaskRepository);
7
8
  private ensureInitialized;
8
9
  /**
9
10
  * Build comprehensive context for AI operations
@@ -1 +1 @@
1
- {"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../src/lib/context-builder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,WAAW,EAAa,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAI3E,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,WAAW,CAAS;;IAM5B,OAAO,CAAC,iBAAiB;IAUzB;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IA0CxD;;OAEG;IACG,sBAAsB,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC;IAsBvB;;OAEG;IACH,OAAO,CAAC,cAAc;IA6CtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAmB1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;OAEG;IACH,oBAAoB,CAAC,aAAa,EAAE,iBAAiB,GAAG,OAAO;IAK/D;;OAEG;IACH,oBAAoB,CAAC,aAAa,EAAE,iBAAiB,GAAG,OAAO;IAK/D;;OAEG;IACH,OAAO,CAAC,aAAa;IAqBrB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA0C7B;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;CAmDjD"}
1
+ {"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../src/lib/context-builder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,WAAW,EAAa,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,cAAc;IAInC,OAAO,CAAC,iBAAiB;IASzB;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAuCxD;;OAEG;IACG,sBAAsB,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC;IAsBvB;;OAEG;IACH,OAAO,CAAC,cAAc;IA6CtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAmB1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAkB7B;;OAEG;IACH,oBAAoB,CAAC,aAAa,EAAE,iBAAiB,GAAG,OAAO;IAK/D;;OAEG;IACH,oBAAoB,CAAC,aAAa,EAAE,iBAAiB,GAAG,OAAO;IAK/D;;OAEG;IACH,OAAO,CAAC,aAAa;IAqBrB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA0C7B;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;CAmDjD"}
@@ -3,20 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ContextBuilder = void 0;
4
4
  const fs_1 = require("fs");
5
5
  const path_1 = require("path");
6
- const storage_1 = require("./storage");
7
6
  const config_1 = require("./config");
8
7
  class ContextBuilder {
9
- storage = null;
8
+ storage;
10
9
  taskOMatic = null;
11
10
  initialized = false;
12
- constructor() {
13
- // Pure constructor - NO side effects
11
+ constructor(storage) {
12
+ this.storage = storage;
14
13
  }
15
14
  ensureInitialized() {
16
15
  if (this.initialized) {
17
16
  return;
18
17
  }
19
- this.storage = new storage_1.LocalStorage();
20
18
  this.taskOMatic = config_1.configManager.getTaskOMaticDir();
21
19
  this.initialized = true;
22
20
  }
@@ -25,9 +23,6 @@ class ContextBuilder {
25
23
  */
26
24
  async buildContext(taskId) {
27
25
  this.ensureInitialized();
28
- if (!this.storage) {
29
- throw new Error("ContextBuilder not initialized");
30
- }
31
26
  const task = await this.storage.getTask(taskId);
32
27
  if (!task) {
33
28
  throw new Error(`Task with ID ${taskId} not found`);
@@ -0,0 +1,6 @@
1
+ import { ExternalExecutor } from "../../types";
2
+ export declare class ClaudeCodeExecutor implements ExternalExecutor {
3
+ name: string;
4
+ execute(message: string, dry?: boolean): Promise<void>;
5
+ }
6
+ //# sourceMappingURL=claude-code-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code-executor.d.ts","sourceRoot":"","sources":["../../../src/lib/executors/claude-code-executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAI/C,qBAAa,kBAAmB,YAAW,gBAAgB;IACzD,IAAI,SAAY;IAEV,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;CA+BpE"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ClaudeCodeExecutor = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const child_process_1 = require("child_process");
9
+ class ClaudeCodeExecutor {
10
+ name = "claude";
11
+ async execute(message, dry = false) {
12
+ if (dry) {
13
+ console.log(chalk_1.default.cyan(`🔧 Using executor: ${this.name}`));
14
+ console.log(chalk_1.default.cyan(`claude -p "${message}"`));
15
+ return;
16
+ }
17
+ // Launch claude and wait for it to complete
18
+ const child = (0, child_process_1.spawn)("claude", ["-p", message], {
19
+ stdio: "inherit", // Give tool full terminal control
20
+ });
21
+ // Wait for completion (blocking)
22
+ await new Promise((resolve, reject) => {
23
+ child.on("close", (code) => {
24
+ if (code === 0) {
25
+ console.log("✅ Claude Code execution completed successfully");
26
+ resolve();
27
+ }
28
+ else {
29
+ const error = new Error(`Claude Code exited with code ${code}`);
30
+ console.error(`❌ ${error.message}`);
31
+ reject(error);
32
+ }
33
+ });
34
+ child.on("error", (error) => {
35
+ console.error(`❌ Failed to launch Claude Code: ${error.message}`);
36
+ reject(error);
37
+ });
38
+ });
39
+ }
40
+ }
41
+ exports.ClaudeCodeExecutor = ClaudeCodeExecutor;
@@ -0,0 +1,6 @@
1
+ import { ExternalExecutor } from "../../types";
2
+ export declare class CodexExecutor implements ExternalExecutor {
3
+ name: string;
4
+ execute(message: string, dry?: boolean): Promise<void>;
5
+ }
6
+ //# sourceMappingURL=codex-executor.d.ts.map