@posthog/agent 1.21.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 (119) hide show
  1. package/CLAUDE.md +3 -3
  2. package/README.md +3 -3
  3. package/dist/claude-cli/cli.js +1396 -1347
  4. package/dist/index.d.ts +11 -11
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +3 -3
  7. package/dist/src/adapters/claude/claude-adapter.d.ts +3 -3
  8. package/dist/src/adapters/claude/claude-adapter.d.ts.map +1 -1
  9. package/dist/src/adapters/claude/claude-adapter.js +156 -111
  10. package/dist/src/adapters/claude/claude-adapter.js.map +1 -1
  11. package/dist/src/adapters/claude/tool-mapper.d.ts +1 -1
  12. package/dist/src/adapters/claude/tool-mapper.d.ts.map +1 -1
  13. package/dist/src/adapters/claude/tool-mapper.js.map +1 -1
  14. package/dist/src/adapters/types.d.ts +1 -1
  15. package/dist/src/adapters/types.d.ts.map +1 -1
  16. package/dist/src/agent.d.ts +7 -7
  17. package/dist/src/agent.d.ts.map +1 -1
  18. package/dist/src/agent.js +143 -85
  19. package/dist/src/agent.js.map +1 -1
  20. package/dist/src/agents/execution.js.map +1 -1
  21. package/dist/src/agents/planning.js.map +1 -1
  22. package/dist/src/agents/research.js.map +1 -1
  23. package/dist/src/file-manager.d.ts +4 -4
  24. package/dist/src/file-manager.d.ts.map +1 -1
  25. package/dist/src/file-manager.js +59 -58
  26. package/dist/src/file-manager.js.map +1 -1
  27. package/dist/src/git-manager.d.ts +2 -1
  28. package/dist/src/git-manager.d.ts.map +1 -1
  29. package/dist/src/git-manager.js +99 -68
  30. package/dist/src/git-manager.js.map +1 -1
  31. package/dist/src/posthog-api.d.ts +2 -3
  32. package/dist/src/posthog-api.d.ts.map +1 -1
  33. package/dist/src/posthog-api.js +22 -22
  34. package/dist/src/posthog-api.js.map +1 -1
  35. package/dist/src/prompt-builder.d.ts +3 -3
  36. package/dist/src/prompt-builder.d.ts.map +1 -1
  37. package/dist/src/prompt-builder.js +123 -93
  38. package/dist/src/prompt-builder.js.map +1 -1
  39. package/dist/src/task-manager.d.ts +4 -4
  40. package/dist/src/task-manager.d.ts.map +1 -1
  41. package/dist/src/task-manager.js +19 -18
  42. package/dist/src/task-manager.js.map +1 -1
  43. package/dist/src/task-progress-reporter.d.ts +3 -4
  44. package/dist/src/task-progress-reporter.d.ts.map +1 -1
  45. package/dist/src/task-progress-reporter.js +69 -53
  46. package/dist/src/task-progress-reporter.js.map +1 -1
  47. package/dist/src/template-manager.d.ts +1 -1
  48. package/dist/src/template-manager.d.ts.map +1 -1
  49. package/dist/src/template-manager.js +30 -28
  50. package/dist/src/template-manager.js.map +1 -1
  51. package/dist/src/todo-manager.d.ts +3 -3
  52. package/dist/src/todo-manager.d.ts.map +1 -1
  53. package/dist/src/todo-manager.js +29 -24
  54. package/dist/src/todo-manager.js.map +1 -1
  55. package/dist/src/tools/registry.d.ts +1 -1
  56. package/dist/src/tools/registry.js +60 -60
  57. package/dist/src/tools/registry.js.map +1 -1
  58. package/dist/src/tools/types.d.ts +31 -31
  59. package/dist/src/types.d.ts +33 -33
  60. package/dist/src/types.d.ts.map +1 -1
  61. package/dist/src/types.js.map +1 -1
  62. package/dist/src/utils/logger.d.ts +4 -4
  63. package/dist/src/utils/logger.d.ts.map +1 -1
  64. package/dist/src/utils/logger.js +8 -8
  65. package/dist/src/utils/logger.js.map +1 -1
  66. package/dist/src/workflow/config.d.ts +1 -1
  67. package/dist/src/workflow/config.d.ts.map +1 -1
  68. package/dist/src/workflow/config.js +18 -18
  69. package/dist/src/workflow/config.js.map +1 -1
  70. package/dist/src/workflow/steps/build.d.ts +1 -1
  71. package/dist/src/workflow/steps/build.d.ts.map +1 -1
  72. package/dist/src/workflow/steps/build.js +46 -38
  73. package/dist/src/workflow/steps/build.js.map +1 -1
  74. package/dist/src/workflow/steps/finalize.d.ts +1 -1
  75. package/dist/src/workflow/steps/finalize.d.ts.map +1 -1
  76. package/dist/src/workflow/steps/finalize.js +62 -47
  77. package/dist/src/workflow/steps/finalize.js.map +1 -1
  78. package/dist/src/workflow/steps/plan.d.ts +1 -1
  79. package/dist/src/workflow/steps/plan.d.ts.map +1 -1
  80. package/dist/src/workflow/steps/plan.js +58 -46
  81. package/dist/src/workflow/steps/plan.js.map +1 -1
  82. package/dist/src/workflow/steps/research.d.ts +1 -1
  83. package/dist/src/workflow/steps/research.d.ts.map +1 -1
  84. package/dist/src/workflow/steps/research.js +68 -56
  85. package/dist/src/workflow/steps/research.js.map +1 -1
  86. package/dist/src/workflow/types.d.ts +12 -12
  87. package/dist/src/workflow/types.d.ts.map +1 -1
  88. package/dist/src/workflow/utils.d.ts +1 -1
  89. package/dist/src/workflow/utils.d.ts.map +1 -1
  90. package/dist/src/workflow/utils.js +7 -4
  91. package/dist/src/workflow/utils.js.map +1 -1
  92. package/package.json +9 -9
  93. package/src/adapters/claude/claude-adapter.ts +220 -168
  94. package/src/adapters/claude/tool-mapper.ts +2 -2
  95. package/src/adapters/types.ts +1 -1
  96. package/src/agent.ts +579 -444
  97. package/src/agents/execution.ts +1 -1
  98. package/src/agents/planning.ts +1 -1
  99. package/src/agents/research.ts +0 -1
  100. package/src/file-manager.ts +64 -63
  101. package/src/git-manager.ts +159 -86
  102. package/src/posthog-api.ts +122 -82
  103. package/src/prompt-builder.ts +180 -135
  104. package/src/task-manager.ts +38 -30
  105. package/src/task-progress-reporter.ts +80 -58
  106. package/src/template-manager.ts +98 -45
  107. package/src/todo-manager.ts +35 -30
  108. package/src/tools/registry.ts +62 -62
  109. package/src/tools/types.ts +36 -36
  110. package/src/types.ts +93 -71
  111. package/src/utils/logger.ts +62 -56
  112. package/src/workflow/config.ts +48 -48
  113. package/src/workflow/steps/build.ts +122 -113
  114. package/src/workflow/steps/finalize.ts +218 -177
  115. package/src/workflow/steps/plan.ts +151 -131
  116. package/src/workflow/steps/research.ts +205 -186
  117. package/src/workflow/types.ts +38 -36
  118. package/src/workflow/utils.ts +37 -34
  119. package/LICENSE +0 -33
@@ -1,207 +1,248 @@
1
- import type { LocalArtifact } from '../../file-manager.js';
2
- import type { Task, TaskRunArtifact } from '../../types.js';
3
- import type { WorkflowStepRunner } from '../types.js';
1
+ import type { LocalArtifact } from "../../file-manager.js";
2
+ import type { Task, TaskRunArtifact } from "../../types.js";
3
+ import type { WorkflowStepRunner } from "../types.js";
4
+ import { finalizeStepGitActions } from "../utils.js";
4
5
 
5
6
  const MAX_SNIPPET_LENGTH = 1200;
6
7
 
7
8
  export const finalizeStep: WorkflowStepRunner = async ({ step, context }) => {
8
- const {
9
- task,
10
- logger,
11
- fileManager,
12
- gitManager,
13
- posthogAPI,
14
- progressReporter,
15
- } = context;
16
-
17
- const stepLogger = logger.child('FinalizeStep');
18
- const artifacts = await fileManager.collectTaskArtifacts(task.id);
19
- let uploadedArtifacts: TaskRunArtifact[] | undefined;
20
-
21
- if (artifacts.length && posthogAPI && progressReporter.runId) {
22
- try {
23
- const payload = artifacts.map((artifact) => ({
24
- name: artifact.name,
25
- type: artifact.type,
26
- content: artifact.content,
27
- content_type: artifact.contentType,
28
- }));
29
- uploadedArtifacts = await posthogAPI.uploadTaskArtifacts(task.id, progressReporter.runId, payload);
30
- stepLogger.info('Uploaded task artifacts to PostHog', {
31
- taskId: task.id,
32
- uploadedCount: uploadedArtifacts.length,
33
- });
34
- } catch (error) {
35
- stepLogger.warn('Failed to upload task artifacts', {
36
- taskId: task.id,
37
- error: error instanceof Error ? error.message : String(error),
38
- });
39
- }
40
- } else {
41
- stepLogger.debug('Skipping artifact upload', {
42
- hasArtifacts: artifacts.length > 0,
43
- hasPostHogApi: Boolean(posthogAPI),
44
- runId: progressReporter.runId,
45
- });
9
+ const {
10
+ task,
11
+ logger,
12
+ fileManager,
13
+ gitManager,
14
+ posthogAPI,
15
+ progressReporter,
16
+ } = context;
17
+
18
+ const stepLogger = logger.child("FinalizeStep");
19
+ const artifacts = await fileManager.collectTaskArtifacts(task.id);
20
+ let uploadedArtifacts: TaskRunArtifact[] | undefined;
21
+
22
+ if (artifacts.length && posthogAPI && progressReporter.runId) {
23
+ try {
24
+ const payload = artifacts.map((artifact) => ({
25
+ name: artifact.name,
26
+ type: artifact.type,
27
+ content: artifact.content,
28
+ content_type: artifact.contentType,
29
+ }));
30
+ uploadedArtifacts = await posthogAPI.uploadTaskArtifacts(
31
+ task.id,
32
+ progressReporter.runId,
33
+ payload,
34
+ );
35
+ stepLogger.info("Uploaded task artifacts to PostHog", {
36
+ taskId: task.id,
37
+ uploadedCount: uploadedArtifacts.length,
38
+ });
39
+ } catch (error) {
40
+ stepLogger.warn("Failed to upload task artifacts", {
41
+ taskId: task.id,
42
+ error: error instanceof Error ? error.message : String(error),
43
+ });
46
44
  }
47
-
48
- const prBody = buildPullRequestBody(task, artifacts, uploadedArtifacts);
49
- await fileManager.cleanupTaskDirectory(task.id);
50
- await gitManager.addAllPostHogFiles();
51
-
52
- context.stepResults[step.id] = {
53
- prBody,
54
- uploadedArtifacts,
55
- artifactCount: artifacts.length,
56
- };
57
-
58
- return { status: 'completed' };
45
+ } else {
46
+ stepLogger.debug("Skipping artifact upload", {
47
+ hasArtifacts: artifacts.length > 0,
48
+ hasPostHogApi: Boolean(posthogAPI),
49
+ runId: progressReporter.runId,
50
+ });
51
+ }
52
+
53
+ const prBody = buildPullRequestBody(task, artifacts, uploadedArtifacts);
54
+ await fileManager.cleanupTaskDirectory(task.id);
55
+ await gitManager.addAllPostHogFiles();
56
+
57
+ // Commit the deletion of artifacts
58
+ await finalizeStepGitActions(context, step, {
59
+ commitMessage: `Cleanup task artifacts for ${task.title}`,
60
+ allowEmptyCommit: true,
61
+ });
62
+
63
+ context.stepResults[step.id] = {
64
+ prBody,
65
+ uploadedArtifacts,
66
+ artifactCount: artifacts.length,
67
+ };
68
+
69
+ return { status: "completed" };
59
70
  };
60
71
 
61
- function buildPullRequestBody(task: Task, artifacts: LocalArtifact[], uploaded?: TaskRunArtifact[]): string {
62
- const lines: string[] = [];
63
- const taskSlug = (task as any).slug || task.id;
64
-
65
- lines.push('## Task context');
66
- lines.push(`- **Task**: ${taskSlug}`);
67
- lines.push(`- **Title**: ${task.title}`);
68
- lines.push(`- **Origin**: ${task.origin_product}`);
69
-
70
- if (task.description) {
71
- lines.push('');
72
- lines.push('> ' + task.description.trim().split('\n').join('\n> '));
73
- }
74
-
75
- const usedFiles = new Set<string>();
76
-
77
- const contextArtifact = artifacts.find((artifact) => artifact.name === 'context.md');
78
- if (contextArtifact) {
79
- lines.push('');
80
- lines.push('### Task prompt');
81
- lines.push(renderCodeFence(contextArtifact.content));
82
- usedFiles.add(contextArtifact.name);
83
- }
84
-
85
- const researchArtifact = artifacts.find((artifact) => artifact.name === 'research.json');
86
- if (researchArtifact) {
87
- usedFiles.add(researchArtifact.name);
88
- const researchSection = formatResearchSection(researchArtifact.content);
89
- if (researchSection) {
90
- lines.push('');
91
- lines.push(researchSection);
92
- }
93
- }
94
-
95
- const planArtifact = artifacts.find((artifact) => artifact.name === 'plan.md');
96
- if (planArtifact) {
97
- lines.push('');
98
- lines.push('### Implementation plan');
99
- lines.push(renderCodeFence(planArtifact.content));
100
- usedFiles.add(planArtifact.name);
72
+ function buildPullRequestBody(
73
+ task: Task,
74
+ artifacts: LocalArtifact[],
75
+ uploaded?: TaskRunArtifact[],
76
+ ): string {
77
+ const lines: string[] = [];
78
+ const taskSlug = (task as unknown as Record<string, unknown>).slug || task.id;
79
+
80
+ lines.push("## Task context");
81
+ lines.push(`- **Task**: ${taskSlug}`);
82
+ lines.push(`- **Title**: ${task.title}`);
83
+ lines.push(`- **Origin**: ${task.origin_product}`);
84
+
85
+ if (task.description) {
86
+ lines.push("");
87
+ lines.push(`> ${task.description.trim().split("\n").join("\n> ")}`);
88
+ }
89
+
90
+ const usedFiles = new Set<string>();
91
+
92
+ const contextArtifact = artifacts.find(
93
+ (artifact) => artifact.name === "context.md",
94
+ );
95
+ if (contextArtifact) {
96
+ lines.push("");
97
+ lines.push("### Task prompt");
98
+ lines.push(contextArtifact.content);
99
+ usedFiles.add(contextArtifact.name);
100
+ }
101
+
102
+ const researchArtifact = artifacts.find(
103
+ (artifact) => artifact.name === "research.json",
104
+ );
105
+ if (researchArtifact) {
106
+ usedFiles.add(researchArtifact.name);
107
+ const researchSection = formatResearchSection(researchArtifact.content);
108
+ if (researchSection) {
109
+ lines.push("");
110
+ lines.push(researchSection);
101
111
  }
102
-
103
- const todoArtifact = artifacts.find((artifact) => artifact.name === 'todos.json');
104
- if (todoArtifact) {
105
- const summary = summarizeTodos(todoArtifact.content);
106
- if (summary) {
107
- lines.push('');
108
- lines.push('### Todo list');
109
- lines.push(summary);
110
- }
111
- usedFiles.add(todoArtifact.name);
112
+ }
113
+
114
+ const planArtifact = artifacts.find(
115
+ (artifact) => artifact.name === "plan.md",
116
+ );
117
+ if (planArtifact) {
118
+ lines.push("");
119
+ lines.push("### Implementation plan");
120
+ lines.push(planArtifact.content);
121
+ usedFiles.add(planArtifact.name);
122
+ }
123
+
124
+ const todoArtifact = artifacts.find(
125
+ (artifact) => artifact.name === "todos.json",
126
+ );
127
+ if (todoArtifact) {
128
+ const summary = summarizeTodos(todoArtifact.content);
129
+ if (summary) {
130
+ lines.push("");
131
+ lines.push("### Todo list");
132
+ lines.push(summary);
112
133
  }
113
-
114
- const remainingArtifacts = artifacts.filter((artifact) => !usedFiles.has(artifact.name));
115
- if (remainingArtifacts.length) {
116
- lines.push('');
117
- lines.push('### Additional artifacts');
118
- for (const artifact of remainingArtifacts) {
119
- lines.push(`#### ${artifact.name}`);
120
- lines.push(renderCodeFence(artifact.content));
121
- }
134
+ usedFiles.add(todoArtifact.name);
135
+ }
136
+
137
+ const remainingArtifacts = artifacts.filter(
138
+ (artifact) => !usedFiles.has(artifact.name),
139
+ );
140
+ if (remainingArtifacts.length) {
141
+ lines.push("");
142
+ lines.push("### Additional artifacts");
143
+ for (const artifact of remainingArtifacts) {
144
+ lines.push(`#### ${artifact.name}`);
145
+ lines.push(renderCodeFence(artifact.content));
122
146
  }
147
+ }
123
148
 
124
- const artifactList = uploaded ?? artifacts.map((artifact) => ({
125
- name: artifact.name,
126
- type: artifact.type,
149
+ const artifactList =
150
+ uploaded ??
151
+ artifacts.map((artifact) => ({
152
+ name: artifact.name,
153
+ type: artifact.type,
127
154
  }));
128
155
 
129
- if (artifactList.length) {
130
- lines.push('');
131
- lines.push('### Uploaded artifacts');
132
- for (const artifact of artifactList) {
133
- const storage = 'storage_path' in artifact && artifact.storage_path ? ` – \`${artifact.storage_path}\`` : '';
134
- lines.push(`- ${artifact.name} (${artifact.type})${storage}`);
135
- }
156
+ if (artifactList.length) {
157
+ lines.push("");
158
+ lines.push("### Uploaded artifacts");
159
+ for (const artifact of artifactList) {
160
+ const rawStoragePath =
161
+ "storage_path" in artifact
162
+ ? (artifact as Record<string, unknown>).storage_path
163
+ : undefined;
164
+ const storagePath =
165
+ typeof rawStoragePath === "string" ? rawStoragePath : undefined;
166
+ const storage =
167
+ storagePath && storagePath.trim().length > 0
168
+ ? ` – \`${storagePath.trim()}\``
169
+ : "";
170
+ lines.push(`- ${artifact.name} (${artifact.type})${storage}`);
136
171
  }
172
+ }
137
173
 
138
- return lines.join('\n\n');
174
+ return lines.join("\n\n");
139
175
  }
140
176
 
141
177
  function renderCodeFence(content: string): string {
142
- const snippet = truncate(content, MAX_SNIPPET_LENGTH);
143
- return ['```', snippet, '```'].join('\n');
178
+ const snippet = truncate(content, MAX_SNIPPET_LENGTH);
179
+ return ["```", snippet, "```"].join("\n");
144
180
  }
145
181
 
146
182
  function truncate(value: string, maxLength: number): string {
147
- if (value.length <= maxLength) {
148
- return value;
149
- }
150
- return `${value.slice(0, maxLength)}\n…`;
183
+ if (value.length <= maxLength) {
184
+ return value;
185
+ }
186
+ return `${value.slice(0, maxLength)}\n…`;
151
187
  }
152
188
 
153
189
  function formatResearchSection(content: string): string | null {
154
- try {
155
- const parsed = JSON.parse(content);
156
- const sections: string[] = [];
157
-
158
- if (parsed.context) {
159
- sections.push('### Research summary');
160
- sections.push(parsed.context);
161
- }
162
-
163
- if (parsed.questions && parsed.questions.length) {
164
- sections.push('');
165
- sections.push('### Questions needing answers');
166
- for (const question of parsed.questions) {
167
- sections.push(`- ${question.question ?? question}`);
168
- }
169
- }
170
-
171
- if (parsed.answers && parsed.answers.length) {
172
- sections.push('');
173
- sections.push('### Answers provided');
174
- for (const answer of parsed.answers) {
175
- const questionId = answer.questionId ? ` (Q: ${answer.questionId})` : '';
176
- sections.push(`- ${answer.selectedOption || answer.customInput || 'answer'}${questionId}`);
177
- }
178
- }
179
-
180
- return sections.length ? sections.join('\n') : null;
181
- } catch {
182
- return null;
190
+ try {
191
+ const parsed = JSON.parse(content);
192
+ const sections: string[] = [];
193
+
194
+ if (parsed.context) {
195
+ sections.push("### Research summary");
196
+ sections.push(parsed.context);
183
197
  }
198
+
199
+ if (parsed.questions?.length) {
200
+ sections.push("");
201
+ sections.push("### Questions needing answers");
202
+ for (const question of parsed.questions) {
203
+ sections.push(`- ${question.question ?? question}`);
204
+ }
205
+ }
206
+
207
+ if (parsed.answers?.length) {
208
+ sections.push("");
209
+ sections.push("### Answers provided");
210
+ for (const answer of parsed.answers) {
211
+ const questionId = answer.questionId
212
+ ? ` (Q: ${answer.questionId})`
213
+ : "";
214
+ sections.push(
215
+ `- ${answer.selectedOption || answer.customInput || "answer"}${questionId}`,
216
+ );
217
+ }
218
+ }
219
+
220
+ return sections.length ? sections.join("\n") : null;
221
+ } catch {
222
+ return null;
223
+ }
184
224
  }
185
225
 
186
226
  function summarizeTodos(content: string): string | null {
187
- try {
188
- const data = JSON.parse(content);
189
- const total = data?.metadata?.total ?? data?.items?.length;
190
- const completed = data?.metadata?.completed ?? data?.items?.filter((item: any) => item.status === 'completed').length;
191
-
192
- const lines = [
193
- `Progress: ${completed}/${total} completed`,
194
- ];
195
-
196
- if (data?.items?.length) {
197
- for (const item of data.items) {
198
- lines.push(`- [${item.status}] ${item.content}`);
199
- }
200
- }
201
-
202
- return lines.join('\n');
203
- } catch {
204
- return null;
227
+ try {
228
+ const data = JSON.parse(content);
229
+ const total = data?.metadata?.total ?? data?.items?.length;
230
+ const completed =
231
+ data?.metadata?.completed ??
232
+ data?.items?.filter(
233
+ (item: { status?: string }) => item.status === "completed",
234
+ ).length;
235
+
236
+ const lines = [`Progress: ${completed}/${total} completed`];
237
+
238
+ if (data?.items?.length) {
239
+ for (const item of data.items) {
240
+ lines.push(`- [${item.status}] ${item.content}`);
241
+ }
205
242
  }
206
- }
207
243
 
244
+ return lines.join("\n");
245
+ } catch {
246
+ return null;
247
+ }
248
+ }