@posthog/agent 1.22.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CLAUDE.md +3 -3
  2. package/README.md +3 -3
  3. package/dist/index.d.ts +11 -11
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +3 -3
  6. package/dist/src/adapters/claude/claude-adapter.d.ts +3 -3
  7. package/dist/src/adapters/claude/claude-adapter.d.ts.map +1 -1
  8. package/dist/src/adapters/claude/claude-adapter.js +156 -111
  9. package/dist/src/adapters/claude/claude-adapter.js.map +1 -1
  10. package/dist/src/adapters/claude/tool-mapper.d.ts +1 -1
  11. package/dist/src/adapters/claude/tool-mapper.d.ts.map +1 -1
  12. package/dist/src/adapters/claude/tool-mapper.js.map +1 -1
  13. package/dist/src/adapters/types.d.ts +1 -1
  14. package/dist/src/adapters/types.d.ts.map +1 -1
  15. package/dist/src/agent.d.ts +7 -7
  16. package/dist/src/agent.d.ts.map +1 -1
  17. package/dist/src/agent.js +143 -85
  18. package/dist/src/agent.js.map +1 -1
  19. package/dist/src/agents/execution.js.map +1 -1
  20. package/dist/src/agents/planning.js.map +1 -1
  21. package/dist/src/agents/research.js.map +1 -1
  22. package/dist/src/file-manager.d.ts +4 -4
  23. package/dist/src/file-manager.d.ts.map +1 -1
  24. package/dist/src/file-manager.js +59 -58
  25. package/dist/src/file-manager.js.map +1 -1
  26. package/dist/src/git-manager.d.ts +1 -1
  27. package/dist/src/git-manager.d.ts.map +1 -1
  28. package/dist/src/git-manager.js +93 -69
  29. package/dist/src/git-manager.js.map +1 -1
  30. package/dist/src/posthog-api.d.ts +2 -3
  31. package/dist/src/posthog-api.d.ts.map +1 -1
  32. package/dist/src/posthog-api.js +22 -22
  33. package/dist/src/posthog-api.js.map +1 -1
  34. package/dist/src/prompt-builder.d.ts +3 -3
  35. package/dist/src/prompt-builder.d.ts.map +1 -1
  36. package/dist/src/prompt-builder.js +123 -93
  37. package/dist/src/prompt-builder.js.map +1 -1
  38. package/dist/src/task-manager.d.ts +4 -4
  39. package/dist/src/task-manager.d.ts.map +1 -1
  40. package/dist/src/task-manager.js +19 -18
  41. package/dist/src/task-manager.js.map +1 -1
  42. package/dist/src/task-progress-reporter.d.ts +3 -4
  43. package/dist/src/task-progress-reporter.d.ts.map +1 -1
  44. package/dist/src/task-progress-reporter.js +59 -54
  45. package/dist/src/task-progress-reporter.js.map +1 -1
  46. package/dist/src/template-manager.d.ts +1 -1
  47. package/dist/src/template-manager.d.ts.map +1 -1
  48. package/dist/src/template-manager.js +30 -28
  49. package/dist/src/template-manager.js.map +1 -1
  50. package/dist/src/todo-manager.d.ts +3 -3
  51. package/dist/src/todo-manager.d.ts.map +1 -1
  52. package/dist/src/todo-manager.js +29 -24
  53. package/dist/src/todo-manager.js.map +1 -1
  54. package/dist/src/tools/registry.d.ts +1 -1
  55. package/dist/src/tools/registry.js +60 -60
  56. package/dist/src/tools/registry.js.map +1 -1
  57. package/dist/src/tools/types.d.ts +31 -31
  58. package/dist/src/types.d.ts +33 -33
  59. package/dist/src/types.d.ts.map +1 -1
  60. package/dist/src/types.js.map +1 -1
  61. package/dist/src/utils/logger.d.ts +4 -4
  62. package/dist/src/utils/logger.d.ts.map +1 -1
  63. package/dist/src/utils/logger.js +8 -8
  64. package/dist/src/utils/logger.js.map +1 -1
  65. package/dist/src/workflow/config.d.ts +1 -1
  66. package/dist/src/workflow/config.d.ts.map +1 -1
  67. package/dist/src/workflow/config.js +18 -18
  68. package/dist/src/workflow/config.js.map +1 -1
  69. package/dist/src/workflow/steps/build.d.ts +1 -1
  70. package/dist/src/workflow/steps/build.d.ts.map +1 -1
  71. package/dist/src/workflow/steps/build.js +46 -38
  72. package/dist/src/workflow/steps/build.js.map +1 -1
  73. package/dist/src/workflow/steps/finalize.d.ts +1 -1
  74. package/dist/src/workflow/steps/finalize.d.ts.map +1 -1
  75. package/dist/src/workflow/steps/finalize.js +54 -48
  76. package/dist/src/workflow/steps/finalize.js.map +1 -1
  77. package/dist/src/workflow/steps/plan.d.ts +1 -1
  78. package/dist/src/workflow/steps/plan.d.ts.map +1 -1
  79. package/dist/src/workflow/steps/plan.js +58 -46
  80. package/dist/src/workflow/steps/plan.js.map +1 -1
  81. package/dist/src/workflow/steps/research.d.ts +1 -1
  82. package/dist/src/workflow/steps/research.d.ts.map +1 -1
  83. package/dist/src/workflow/steps/research.js +68 -56
  84. package/dist/src/workflow/steps/research.js.map +1 -1
  85. package/dist/src/workflow/types.d.ts +12 -12
  86. package/dist/src/workflow/types.d.ts.map +1 -1
  87. package/dist/src/workflow/utils.d.ts +1 -1
  88. package/dist/src/workflow/utils.d.ts.map +1 -1
  89. package/dist/src/workflow/utils.js +7 -4
  90. package/dist/src/workflow/utils.js.map +1 -1
  91. package/package.json +8 -8
  92. package/src/adapters/claude/claude-adapter.ts +220 -168
  93. package/src/adapters/claude/tool-mapper.ts +2 -2
  94. package/src/adapters/types.ts +1 -1
  95. package/src/agent.ts +579 -444
  96. package/src/agents/execution.ts +1 -1
  97. package/src/agents/planning.ts +1 -1
  98. package/src/agents/research.ts +0 -1
  99. package/src/file-manager.ts +64 -63
  100. package/src/git-manager.ts +152 -87
  101. package/src/posthog-api.ts +122 -82
  102. package/src/prompt-builder.ts +180 -135
  103. package/src/task-manager.ts +38 -30
  104. package/src/task-progress-reporter.ts +70 -59
  105. package/src/template-manager.ts +98 -45
  106. package/src/todo-manager.ts +35 -30
  107. package/src/tools/registry.ts +62 -62
  108. package/src/tools/types.ts +36 -36
  109. package/src/types.ts +93 -71
  110. package/src/utils/logger.ts +62 -56
  111. package/src/workflow/config.ts +48 -48
  112. package/src/workflow/steps/build.ts +122 -113
  113. package/src/workflow/steps/finalize.ts +214 -182
  114. package/src/workflow/steps/plan.ts +151 -131
  115. package/src/workflow/steps/research.ts +205 -186
  116. package/src/workflow/types.ts +38 -36
  117. package/src/workflow/utils.ts +37 -34
  118. package/LICENSE +0 -33
@@ -1,27 +1,30 @@
1
- import type { Task, UrlMention, PostHogResource } from './types.js';
2
- import type { TemplateVariables } from './template-manager.js';
3
- import { Logger } from './utils/logger.js';
4
- import { promises as fs } from 'fs';
5
- import { join } from 'path';
1
+ import { promises as fs } from "node:fs";
2
+ import { join } from "node:path";
3
+ import type { TemplateVariables } from "./template-manager.js";
4
+ import type { PostHogResource, Task, UrlMention } from "./types.js";
5
+ import { Logger } from "./utils/logger.js";
6
6
 
7
7
  export interface PromptBuilderDeps {
8
8
  getTaskFiles: (taskId: string) => Promise<any[]>;
9
9
  generatePlanTemplate: (vars: TemplateVariables) => Promise<string>;
10
- posthogClient?: { fetchResourceByUrl: (mention: UrlMention) => Promise<PostHogResource> };
10
+ posthogClient?: {
11
+ fetchResourceByUrl: (mention: UrlMention) => Promise<PostHogResource>;
12
+ };
11
13
  logger?: Logger;
12
14
  }
13
15
 
14
16
  export class PromptBuilder {
15
- private getTaskFiles: PromptBuilderDeps['getTaskFiles'];
16
- private generatePlanTemplate: PromptBuilderDeps['generatePlanTemplate'];
17
- private posthogClient?: PromptBuilderDeps['posthogClient'];
17
+ private getTaskFiles: PromptBuilderDeps["getTaskFiles"];
18
+ private generatePlanTemplate: PromptBuilderDeps["generatePlanTemplate"];
19
+ private posthogClient?: PromptBuilderDeps["posthogClient"];
18
20
  private logger: Logger;
19
21
 
20
22
  constructor(deps: PromptBuilderDeps) {
21
23
  this.getTaskFiles = deps.getTaskFiles;
22
24
  this.generatePlanTemplate = deps.generatePlanTemplate;
23
25
  this.posthogClient = deps.posthogClient;
24
- this.logger = deps.logger || new Logger({ debug: false, prefix: '[PromptBuilder]' });
26
+ this.logger =
27
+ deps.logger || new Logger({ debug: false, prefix: "[PromptBuilder]" });
25
28
  }
26
29
 
27
30
  /**
@@ -33,8 +36,10 @@ export class PromptBuilder {
33
36
  const paths: string[] = [];
34
37
  let match: RegExpExecArray | null;
35
38
 
36
- while ((match = fileTagRegex.exec(description)) !== null) {
39
+ match = fileTagRegex.exec(description);
40
+ while (match !== null) {
37
41
  paths.push(match[1]);
42
+ match = fileTagRegex.exec(description);
38
43
  }
39
44
 
40
45
  return paths;
@@ -43,13 +48,18 @@ export class PromptBuilder {
43
48
  /**
44
49
  * Read file contents from repository
45
50
  */
46
- private async readFileContent(repositoryPath: string, filePath: string): Promise<string | null> {
51
+ private async readFileContent(
52
+ repositoryPath: string,
53
+ filePath: string,
54
+ ): Promise<string | null> {
47
55
  try {
48
56
  const fullPath = join(repositoryPath, filePath);
49
- const content = await fs.readFile(fullPath, 'utf8');
57
+ const content = await fs.readFile(fullPath, "utf8");
50
58
  return content;
51
59
  } catch (error) {
52
- this.logger.warn(`Failed to read referenced file: ${filePath}`, { error });
60
+ this.logger.warn(`Failed to read referenced file: ${filePath}`, {
61
+ error,
62
+ });
53
63
  return null;
54
64
  }
55
65
  }
@@ -60,30 +70,35 @@ export class PromptBuilder {
60
70
  */
61
71
  private extractUrlMentions(description: string): UrlMention[] {
62
72
  const mentions: UrlMention[] = [];
63
-
73
+
64
74
  // PostHog resource mentions: <error id="..." />, <experiment id="..." />, etc.
65
- const resourceRegex = /<(error|experiment|insight|feature_flag)\s+id="([^"]+)"\s*\/>/g;
75
+ const resourceRegex =
76
+ /<(error|experiment|insight|feature_flag)\s+id="([^"]+)"\s*\/>/g;
66
77
  let match: RegExpExecArray | null;
67
78
 
68
- while ((match = resourceRegex.exec(description)) !== null) {
79
+ match = resourceRegex.exec(description);
80
+ while (match !== null) {
69
81
  const [, type, id] = match;
70
82
  mentions.push({
71
- url: '', // Will be reconstructed if needed
83
+ url: "", // Will be reconstructed if needed
72
84
  type: type as any,
73
85
  id,
74
- label: this.generateUrlLabel('', type as any),
86
+ label: this.generateUrlLabel("", type as any),
75
87
  });
88
+ match = resourceRegex.exec(description);
76
89
  }
77
90
 
78
91
  // Generic URL mentions: <url href="..." />
79
92
  const urlRegex = /<url\s+href="([^"]+)"\s*\/>/g;
80
- while ((match = urlRegex.exec(description)) !== null) {
93
+ match = urlRegex.exec(description);
94
+ while (match !== null) {
81
95
  const [, url] = match;
82
96
  mentions.push({
83
97
  url,
84
- type: 'generic',
85
- label: this.generateUrlLabel(url, 'generic'),
98
+ type: "generic",
99
+ label: this.generateUrlLabel(url, "generic"),
86
100
  });
101
+ match = urlRegex.exec(description);
87
102
  }
88
103
 
89
104
  return mentions;
@@ -96,21 +111,23 @@ export class PromptBuilder {
96
111
  try {
97
112
  const urlObj = new URL(url);
98
113
  switch (type) {
99
- case 'error':
114
+ case "error": {
100
115
  const errorMatch = url.match(/error_tracking\/([a-f0-9-]+)/);
101
- return errorMatch ? `Error ${errorMatch[1].slice(0, 8)}...` : 'Error';
102
- case 'experiment':
116
+ return errorMatch ? `Error ${errorMatch[1].slice(0, 8)}...` : "Error";
117
+ }
118
+ case "experiment": {
103
119
  const expMatch = url.match(/experiments\/(\d+)/);
104
- return expMatch ? `Experiment #${expMatch[1]}` : 'Experiment';
105
- case 'insight':
106
- return 'Insight';
107
- case 'feature_flag':
108
- return 'Feature Flag';
120
+ return expMatch ? `Experiment #${expMatch[1]}` : "Experiment";
121
+ }
122
+ case "insight":
123
+ return "Insight";
124
+ case "feature_flag":
125
+ return "Feature Flag";
109
126
  default:
110
127
  return urlObj.hostname;
111
128
  }
112
129
  } catch {
113
- return 'URL';
130
+ return "URL";
114
131
  }
115
132
  }
116
133
 
@@ -118,7 +135,7 @@ export class PromptBuilder {
118
135
  * Process URL references and fetch their content
119
136
  */
120
137
  private async processUrlReferences(
121
- description: string
138
+ description: string,
122
139
  ): Promise<{ description: string; referencedResources: PostHogResource[] }> {
123
140
  const urlMentions = this.extractUrlMentions(description);
124
141
  const referencedResources: PostHogResource[] = [];
@@ -133,13 +150,15 @@ export class PromptBuilder {
133
150
  const resource = await this.posthogClient.fetchResourceByUrl(mention);
134
151
  referencedResources.push(resource);
135
152
  } catch (error) {
136
- this.logger.warn(`Failed to fetch resource from URL: ${mention.url}`, { error });
153
+ this.logger.warn(`Failed to fetch resource from URL: ${mention.url}`, {
154
+ error,
155
+ });
137
156
  // Add a placeholder resource for failed fetches
138
157
  referencedResources.push({
139
158
  type: mention.type,
140
- id: mention.id || '',
159
+ id: mention.id || "",
141
160
  url: mention.url,
142
- title: mention.label || 'Unknown Resource',
161
+ title: mention.label || "Unknown Resource",
143
162
  content: `Failed to fetch resource from ${mention.url}: ${error}`,
144
163
  metadata: {},
145
164
  });
@@ -149,20 +168,22 @@ export class PromptBuilder {
149
168
  // Replace URL tags with just the label for readability
150
169
  let processedDescription = description;
151
170
  for (const mention of urlMentions) {
152
- if (mention.type === 'generic') {
171
+ if (mention.type === "generic") {
153
172
  // Generic URLs: <url href="..." />
154
- const escapedUrl = mention.url.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
173
+ const escapedUrl = mention.url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
155
174
  processedDescription = processedDescription.replace(
156
- new RegExp(`<url\\s+href="${escapedUrl}"\\s*/>`, 'g'),
157
- `@${mention.label}`
175
+ new RegExp(`<url\\s+href="${escapedUrl}"\\s*/>`, "g"),
176
+ `@${mention.label}`,
158
177
  );
159
178
  } else {
160
179
  // PostHog resources: <error id="..." />, <experiment id="..." />, etc.
161
- const escapedType = mention.type.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
162
- const escapedId = mention.id ? mention.id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') : '';
180
+ const escapedType = mention.type.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
181
+ const escapedId = mention.id
182
+ ? mention.id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
183
+ : "";
163
184
  processedDescription = processedDescription.replace(
164
- new RegExp(`<${escapedType}\\s+id="${escapedId}"\\s*/>`, 'g'),
165
- `@${mention.label}`
185
+ new RegExp(`<${escapedType}\\s+id="${escapedId}"\\s*/>`, "g"),
186
+ `@${mention.label}`,
166
187
  );
167
188
  }
168
189
  }
@@ -176,8 +197,11 @@ export class PromptBuilder {
176
197
  */
177
198
  private async processFileReferences(
178
199
  description: string,
179
- repositoryPath?: string
180
- ): Promise<{ description: string; referencedFiles: Array<{ path: string; content: string }> }> {
200
+ repositoryPath?: string,
201
+ ): Promise<{
202
+ description: string;
203
+ referencedFiles: Array<{ path: string; content: string }>;
204
+ }> {
181
205
  const filePaths = this.extractFilePaths(description);
182
206
  const referencedFiles: Array<{ path: string; content: string }> = [];
183
207
 
@@ -196,211 +220,221 @@ export class PromptBuilder {
196
220
  // Replace file tags with just the filename for readability
197
221
  let processedDescription = description;
198
222
  for (const filePath of filePaths) {
199
- const fileName = filePath.split('/').pop() || filePath;
223
+ const fileName = filePath.split("/").pop() || filePath;
200
224
  processedDescription = processedDescription.replace(
201
- new RegExp(`<file\\s+path="${filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"\\s*/>`, 'g'),
202
- `@${fileName}`
225
+ new RegExp(
226
+ `<file\\s+path="${filePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"\\s*/>`,
227
+ "g",
228
+ ),
229
+ `@${fileName}`,
203
230
  );
204
231
  }
205
232
 
206
233
  return { description: processedDescription, referencedFiles };
207
234
  }
208
235
 
209
- async buildResearchPrompt(task: Task, repositoryPath?: string): Promise<string> {
236
+ async buildResearchPrompt(
237
+ task: Task,
238
+ repositoryPath?: string,
239
+ ): Promise<string> {
210
240
  // Process file references in description
211
- const { description: descriptionAfterFiles, referencedFiles } = await this.processFileReferences(
212
- task.description,
213
- repositoryPath
214
- );
241
+ const { description: descriptionAfterFiles, referencedFiles } =
242
+ await this.processFileReferences(task.description, repositoryPath);
215
243
 
216
244
  // Process URL references in description
217
- const { description: processedDescription, referencedResources } = await this.processUrlReferences(
218
- descriptionAfterFiles
219
- );
245
+ const { description: processedDescription, referencedResources } =
246
+ await this.processUrlReferences(descriptionAfterFiles);
220
247
 
221
- let prompt = '<task>\n';
248
+ let prompt = "<task>\n";
222
249
  prompt += `<title>${task.title}</title>\n`;
223
250
  prompt += `<description>${processedDescription}</description>\n`;
224
251
 
225
252
  if ((task as any).primary_repository) {
226
253
  prompt += `<repository>${(task as any).primary_repository}</repository>\n`;
227
254
  }
228
- prompt += '</task>\n';
255
+ prompt += "</task>\n";
229
256
 
230
257
  // Add referenced files from @ mentions
231
258
  if (referencedFiles.length > 0) {
232
- prompt += '\n<referenced_files>\n';
259
+ prompt += "\n<referenced_files>\n";
233
260
  for (const file of referencedFiles) {
234
261
  prompt += `<file path="${file.path}">\n\`\`\`\n${file.content}\n\`\`\`\n</file>\n`;
235
262
  }
236
- prompt += '</referenced_files>\n';
263
+ prompt += "</referenced_files>\n";
237
264
  }
238
265
 
239
266
  // Add referenced resources from URL mentions
240
267
  if (referencedResources.length > 0) {
241
- prompt += '\n<referenced_resources>\n';
268
+ prompt += "\n<referenced_resources>\n";
242
269
  for (const resource of referencedResources) {
243
270
  prompt += `<resource type="${resource.type}" url="${resource.url}">\n`;
244
271
  prompt += `<title>${resource.title}</title>\n`;
245
272
  prompt += `<content>${resource.content}</content>\n`;
246
- prompt += '</resource>\n';
273
+ prompt += "</resource>\n";
247
274
  }
248
- prompt += '</referenced_resources>\n';
275
+ prompt += "</referenced_resources>\n";
249
276
  }
250
277
 
251
278
  try {
252
279
  const taskFiles = await this.getTaskFiles(task.id);
253
- const contextFiles = taskFiles.filter((f: any) => f.type === 'context' || f.type === 'reference');
280
+ const contextFiles = taskFiles.filter(
281
+ (f: any) => f.type === "context" || f.type === "reference",
282
+ );
254
283
  if (contextFiles.length > 0) {
255
- prompt += '\n<supporting_files>\n';
284
+ prompt += "\n<supporting_files>\n";
256
285
  for (const file of contextFiles) {
257
286
  prompt += `<file name="${file.name}" type="${file.type}">\n${file.content}\n</file>\n`;
258
287
  }
259
- prompt += '</supporting_files>\n';
288
+ prompt += "</supporting_files>\n";
260
289
  }
261
- } catch (error) {
262
- this.logger.debug('No existing task files found for research', { taskId: task.id });
290
+ } catch (_error) {
291
+ this.logger.debug("No existing task files found for research", {
292
+ taskId: task.id,
293
+ });
263
294
  }
264
295
 
265
296
  return prompt;
266
297
  }
267
298
 
268
- async buildPlanningPrompt(task: Task, repositoryPath?: string): Promise<string> {
299
+ async buildPlanningPrompt(
300
+ task: Task,
301
+ repositoryPath?: string,
302
+ ): Promise<string> {
269
303
  // Process file references in description
270
- const { description: descriptionAfterFiles, referencedFiles } = await this.processFileReferences(
271
- task.description,
272
- repositoryPath
273
- );
304
+ const { description: descriptionAfterFiles, referencedFiles } =
305
+ await this.processFileReferences(task.description, repositoryPath);
274
306
 
275
307
  // Process URL references in description
276
- const { description: processedDescription, referencedResources } = await this.processUrlReferences(
277
- descriptionAfterFiles
278
- );
308
+ const { description: processedDescription, referencedResources } =
309
+ await this.processUrlReferences(descriptionAfterFiles);
279
310
 
280
- let prompt = '<task>\n';
311
+ let prompt = "<task>\n";
281
312
  prompt += `<title>${task.title}</title>\n`;
282
313
  prompt += `<description>${processedDescription}</description>\n`;
283
314
 
284
315
  if ((task as any).primary_repository) {
285
316
  prompt += `<repository>${(task as any).primary_repository}</repository>\n`;
286
317
  }
287
- prompt += '</task>\n';
318
+ prompt += "</task>\n";
288
319
 
289
320
  // Add referenced files from @ mentions
290
321
  if (referencedFiles.length > 0) {
291
- prompt += '\n<referenced_files>\n';
322
+ prompt += "\n<referenced_files>\n";
292
323
  for (const file of referencedFiles) {
293
324
  prompt += `<file path="${file.path}">\n\`\`\`\n${file.content}\n\`\`\`\n</file>\n`;
294
325
  }
295
- prompt += '</referenced_files>\n';
326
+ prompt += "</referenced_files>\n";
296
327
  }
297
328
 
298
329
  // Add referenced resources from URL mentions
299
330
  if (referencedResources.length > 0) {
300
- prompt += '\n<referenced_resources>\n';
331
+ prompt += "\n<referenced_resources>\n";
301
332
  for (const resource of referencedResources) {
302
333
  prompt += `<resource type="${resource.type}" url="${resource.url}">\n`;
303
334
  prompt += `<title>${resource.title}</title>\n`;
304
335
  prompt += `<content>${resource.content}</content>\n`;
305
- prompt += '</resource>\n';
336
+ prompt += "</resource>\n";
306
337
  }
307
- prompt += '</referenced_resources>\n';
338
+ prompt += "</referenced_resources>\n";
308
339
  }
309
340
 
310
341
  try {
311
342
  const taskFiles = await this.getTaskFiles(task.id);
312
- const contextFiles = taskFiles.filter((f: any) => f.type === 'context' || f.type === 'reference');
343
+ const contextFiles = taskFiles.filter(
344
+ (f: any) => f.type === "context" || f.type === "reference",
345
+ );
313
346
  if (contextFiles.length > 0) {
314
- prompt += '\n<supporting_files>\n';
347
+ prompt += "\n<supporting_files>\n";
315
348
  for (const file of contextFiles) {
316
349
  prompt += `<file name="${file.name}" type="${file.type}">\n${file.content}\n</file>\n`;
317
350
  }
318
- prompt += '</supporting_files>\n';
351
+ prompt += "</supporting_files>\n";
319
352
  }
320
- } catch (error) {
321
- this.logger.debug('No existing task files found for planning', { taskId: task.id });
353
+ } catch (_error) {
354
+ this.logger.debug("No existing task files found for planning", {
355
+ taskId: task.id,
356
+ });
322
357
  }
323
358
 
324
359
  const templateVariables = {
325
360
  task_id: task.id,
326
361
  task_title: task.title,
327
362
  task_description: processedDescription,
328
- date: new Date().toISOString().split('T')[0],
329
- repository: ((task as any).primary_repository || '') as string,
363
+ date: new Date().toISOString().split("T")[0],
364
+ repository: ((task as any).primary_repository || "") as string,
330
365
  };
331
366
 
332
367
  const planTemplate = await this.generatePlanTemplate(templateVariables);
333
368
 
334
- prompt += '\n<instructions>\n';
335
- prompt += 'Analyze the codebase and create a detailed implementation plan. Use the template structure below, filling each section with specific, actionable information.\n';
336
- prompt += '</instructions>\n\n';
337
- prompt += '<plan_template>\n';
369
+ prompt += "\n<instructions>\n";
370
+ prompt +=
371
+ "Analyze the codebase and create a detailed implementation plan. Use the template structure below, filling each section with specific, actionable information.\n";
372
+ prompt += "</instructions>\n\n";
373
+ prompt += "<plan_template>\n";
338
374
  prompt += planTemplate;
339
- prompt += '\n</plan_template>';
375
+ prompt += "\n</plan_template>";
340
376
 
341
377
  return prompt;
342
378
  }
343
379
 
344
- async buildExecutionPrompt(task: Task, repositoryPath?: string): Promise<string> {
380
+ async buildExecutionPrompt(
381
+ task: Task,
382
+ repositoryPath?: string,
383
+ ): Promise<string> {
345
384
  // Process file references in description
346
- const { description: descriptionAfterFiles, referencedFiles } = await this.processFileReferences(
347
- task.description,
348
- repositoryPath
349
- );
385
+ const { description: descriptionAfterFiles, referencedFiles } =
386
+ await this.processFileReferences(task.description, repositoryPath);
350
387
 
351
388
  // Process URL references in description
352
- const { description: processedDescription, referencedResources } = await this.processUrlReferences(
353
- descriptionAfterFiles
354
- );
389
+ const { description: processedDescription, referencedResources } =
390
+ await this.processUrlReferences(descriptionAfterFiles);
355
391
 
356
- let prompt = '<task>\n';
392
+ let prompt = "<task>\n";
357
393
  prompt += `<title>${task.title}</title>\n`;
358
394
  prompt += `<description>${processedDescription}</description>\n`;
359
395
 
360
396
  if ((task as any).primary_repository) {
361
397
  prompt += `<repository>${(task as any).primary_repository}</repository>\n`;
362
398
  }
363
- prompt += '</task>\n';
399
+ prompt += "</task>\n";
364
400
 
365
401
  // Add referenced files from @ mentions
366
402
  if (referencedFiles.length > 0) {
367
- prompt += '\n<referenced_files>\n';
403
+ prompt += "\n<referenced_files>\n";
368
404
  for (const file of referencedFiles) {
369
405
  prompt += `<file path="${file.path}">\n\`\`\`\n${file.content}\n\`\`\`\n</file>\n`;
370
406
  }
371
- prompt += '</referenced_files>\n';
407
+ prompt += "</referenced_files>\n";
372
408
  }
373
409
 
374
410
  // Add referenced resources from URL mentions
375
411
  if (referencedResources.length > 0) {
376
- prompt += '\n<referenced_resources>\n';
412
+ prompt += "\n<referenced_resources>\n";
377
413
  for (const resource of referencedResources) {
378
414
  prompt += `<resource type="${resource.type}" url="${resource.url}">\n`;
379
415
  prompt += `<title>${resource.title}</title>\n`;
380
416
  prompt += `<content>${resource.content}</content>\n`;
381
- prompt += '</resource>\n';
417
+ prompt += "</resource>\n";
382
418
  }
383
- prompt += '</referenced_resources>\n';
419
+ prompt += "</referenced_resources>\n";
384
420
  }
385
421
 
386
422
  try {
387
423
  const taskFiles = await this.getTaskFiles(task.id);
388
- const hasPlan = taskFiles.some((f: any) => f.type === 'plan');
389
- const todosFile = taskFiles.find((f: any) => f.name === 'todos.json');
424
+ const hasPlan = taskFiles.some((f: any) => f.type === "plan");
425
+ const todosFile = taskFiles.find((f: any) => f.name === "todos.json");
390
426
 
391
427
  if (taskFiles.length > 0) {
392
- prompt += '\n<context>\n';
428
+ prompt += "\n<context>\n";
393
429
  for (const file of taskFiles) {
394
- if (file.type === 'plan') {
430
+ if (file.type === "plan") {
395
431
  prompt += `<plan>\n${file.content}\n</plan>\n`;
396
- } else if (file.name === 'todos.json') {
397
- // skip - we do this below
398
- continue;
432
+ } else if (file.name === "todos.json") {
399
433
  } else {
400
434
  prompt += `<file name="${file.name}" type="${file.type}">\n${file.content}\n</file>\n`;
401
435
  }
402
436
  }
403
- prompt += '</context>\n';
437
+ prompt += "</context>\n";
404
438
  }
405
439
 
406
440
  // Add todos context if resuming work
@@ -408,37 +442,48 @@ export class PromptBuilder {
408
442
  try {
409
443
  const todos = JSON.parse(todosFile.content);
410
444
  if (todos.items && todos.items.length > 0) {
411
- prompt += '\n<previous_todos>\n';
412
- prompt += 'You previously created the following todo list for this task:\n\n';
445
+ prompt += "\n<previous_todos>\n";
446
+ prompt +=
447
+ "You previously created the following todo list for this task:\n\n";
413
448
  for (const item of todos.items) {
414
- const statusIcon = item.status === 'completed' ? '✓' : item.status === 'in_progress' ? '▶' : '○';
449
+ const statusIcon =
450
+ item.status === "completed"
451
+ ? "✓"
452
+ : item.status === "in_progress"
453
+ ? "▶"
454
+ : "○";
415
455
  prompt += `${statusIcon} [${item.status}] ${item.content}\n`;
416
456
  }
417
457
  prompt += `\nProgress: ${todos.metadata.completed}/${todos.metadata.total} completed\n`;
418
- prompt += '\nYou can reference this list when resuming work or create an updated list as needed.\n';
419
- prompt += '</previous_todos>\n';
458
+ prompt +=
459
+ "\nYou can reference this list when resuming work or create an updated list as needed.\n";
460
+ prompt += "</previous_todos>\n";
420
461
  }
421
462
  } catch (error) {
422
- this.logger.debug('Failed to parse todos.json for context', { error });
463
+ this.logger.debug("Failed to parse todos.json for context", {
464
+ error,
465
+ });
423
466
  }
424
467
  }
425
468
 
426
- prompt += '\n<instructions>\n';
469
+ prompt += "\n<instructions>\n";
427
470
  if (hasPlan) {
428
- prompt += 'Implement the changes described in the execution plan. Follow the plan step-by-step and make the necessary file modifications.\n';
471
+ prompt +=
472
+ "Implement the changes described in the execution plan. Follow the plan step-by-step and make the necessary file modifications.\n";
429
473
  } else {
430
- prompt += 'Implement the changes described in the task. Make the necessary file modifications to complete the task.\n';
474
+ prompt +=
475
+ "Implement the changes described in the task. Make the necessary file modifications to complete the task.\n";
431
476
  }
432
- prompt += '</instructions>';
433
- } catch (error) {
434
- this.logger.debug('No supporting files found for execution', { taskId: task.id });
435
- prompt += '\n<instructions>\n';
436
- prompt += 'Implement the changes described in the task.\n';
437
- prompt += '</instructions>';
477
+ prompt += "</instructions>";
478
+ } catch (_error) {
479
+ this.logger.debug("No supporting files found for execution", {
480
+ taskId: task.id,
481
+ });
482
+ prompt += "\n<instructions>\n";
483
+ prompt += "Implement the changes described in the task.\n";
484
+ prompt += "</instructions>";
438
485
  }
439
486
 
440
487
  return prompt;
441
488
  }
442
489
  }
443
-
444
-