@posthog/agent 1.1.0 → 1.3.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 (39) hide show
  1. package/CLAUDE.md +68 -35
  2. package/README.md +55 -14
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/src/agent.d.ts +5 -1
  6. package/dist/src/agent.d.ts.map +1 -1
  7. package/dist/src/agent.js +65 -11
  8. package/dist/src/agent.js.map +1 -1
  9. package/dist/src/event-transformer.d.ts +2 -0
  10. package/dist/src/event-transformer.d.ts.map +1 -1
  11. package/dist/src/event-transformer.js +53 -5
  12. package/dist/src/event-transformer.js.map +1 -1
  13. package/dist/src/posthog-api.d.ts +34 -0
  14. package/dist/src/posthog-api.d.ts.map +1 -1
  15. package/dist/src/posthog-api.js +38 -0
  16. package/dist/src/posthog-api.js.map +1 -1
  17. package/dist/src/stage-executor.d.ts +5 -2
  18. package/dist/src/stage-executor.d.ts.map +1 -1
  19. package/dist/src/stage-executor.js +20 -12
  20. package/dist/src/stage-executor.js.map +1 -1
  21. package/dist/src/task-progress-reporter.d.ts +44 -0
  22. package/dist/src/task-progress-reporter.d.ts.map +1 -0
  23. package/dist/src/task-progress-reporter.js +234 -0
  24. package/dist/src/task-progress-reporter.js.map +1 -0
  25. package/dist/src/types.d.ts +20 -0
  26. package/dist/src/types.d.ts.map +1 -1
  27. package/dist/src/types.js.map +1 -1
  28. package/package.json +2 -1
  29. package/src/agent.ts +77 -11
  30. package/src/event-transformer.ts +61 -7
  31. package/src/posthog-api.ts +79 -0
  32. package/src/stage-executor.ts +29 -15
  33. package/src/task-progress-reporter.ts +287 -0
  34. package/src/types.ts +30 -2
  35. package/dist/src/utils/mcp.d.ts +0 -10
  36. package/dist/src/utils/mcp.d.ts.map +0 -1
  37. package/dist/src/utils/mcp.js +0 -18
  38. package/dist/src/utils/mcp.js.map +0 -1
  39. package/src/utils/mcp.ts +0 -15
package/CLAUDE.md CHANGED
@@ -114,16 +114,43 @@ const task = await agent.fetchTask("task_abc123");
114
114
  const result = await agent.runTask(task, ExecutionMode.PLAN_AND_BUILD);
115
115
  ```
116
116
 
117
- ### Array App Integration
117
+ ### Progress Updates
118
118
  ```typescript
119
- // Fetch task from PostHog and run with selected mode
120
- const result = await agent.runTask(taskId, userSelectedMode, {
121
- repositoryPath: selectedRepoPath,
122
- permissionMode: PermissionMode.DEFAULT,
123
- onEvent: (event) => updateUI(event)
124
- });
119
+ const posthogClient = agent.getPostHogClient();
120
+ const poller = setInterval(async () => {
121
+ const progress = await posthogClient?.getTaskProgress(taskId);
122
+ if (progress?.has_progress) {
123
+ updateUI(progress.status, progress.current_step, progress.completed_steps, progress.total_steps);
124
+ }
125
+ }, 3000);
126
+
127
+ try {
128
+ await agent.runWorkflow(taskId, workflowId, {
129
+ repositoryPath: selectedRepoPath,
130
+ permissionMode: PermissionMode.DEFAULT,
131
+ autoProgress: true,
132
+ });
133
+ } finally {
134
+ clearInterval(poller);
135
+ }
136
+ ```
137
+
138
+ > The agent still emits transformed events via the `onEvent` callback, so UI layers can combine streaming updates with periodic polling if desired.
125
139
 
126
- // Plan is stored in .posthog/{taskId}/plan.md and committed to Git
140
+ ```typescript
141
+ // Handle the hook provided when constructing the Agent
142
+ import type { AgentEvent } from '@posthog/agent';
143
+
144
+ private handleLiveEvent(event: AgentEvent) {
145
+ switch (event.type) {
146
+ case 'status':
147
+ this.updateUI(event.phase, event.stage);
148
+ break;
149
+ case 'error':
150
+ this.showError(event.message);
151
+ break;
152
+ }
153
+ }
127
154
  ```
128
155
 
129
156
  ### Working with Task Files
@@ -212,10 +239,11 @@ await agent.writeTaskFile(task.id, "requirements.md",
212
239
  "context"
213
240
  );
214
241
 
215
- // 4. Execute with PLAN_AND_BUILD mode
216
- const result = await agent.runTask(task, ExecutionMode.PLAN_AND_BUILD, {
242
+ // 4. Execute with PLAN_AND_BUILD mode and rely on PostHog polling for progress
243
+ const result = await agent.runWorkflow(task.id, workflowId, {
244
+ repositoryPath: "/path/to/repo",
217
245
  permissionMode: PermissionMode.DEFAULT,
218
- onEvent: (event) => console.log(event)
246
+ autoProgress: true,
219
247
  });
220
248
 
221
249
  // 5. Review results
@@ -227,31 +255,36 @@ console.log("Plan location:", `.posthog/${task.id}/plan.md`);
227
255
  ### Array App Integration Pattern
228
256
 
229
257
  ```typescript
230
- // How Array app uses the SDK
231
258
  class ArrayTaskExecution {
232
- async executeTask(taskId: string, mode: ExecutionMode, repoPath: string) {
233
- const result = await this.agent.runTask(taskId, mode, {
234
- repositoryPath: repoPath,
235
- permissionMode: PermissionMode.DEFAULT,
236
- onEvent: (event) => this.updateUI(event)
237
- });
238
-
239
- // Show branches created for user review
240
- this.showBranchesForReview(taskId, mode);
241
- return result;
259
+ async executeTask(taskId: string, workflowId: string, repoPath: string) {
260
+ const poller = setInterval(() => this.pollProgress(taskId), 3000);
261
+ try {
262
+ await this.agent.runWorkflow(taskId, workflowId, {
263
+ repositoryPath: repoPath,
264
+ permissionMode: PermissionMode.DEFAULT,
265
+ autoProgress: true,
266
+ });
267
+ } finally {
268
+ clearInterval(poller);
269
+ }
270
+
271
+ this.showBranchesForReview(taskId);
242
272
  }
243
-
244
- private updateUI(event: any) {
245
- switch (event.type) {
246
- case 'status':
247
- this.updateProgressBar(event.data?.status);
248
- break;
249
- case 'file_write':
250
- this.showFileChange(event.data);
251
- break;
252
- case 'done':
253
- this.showCompletion();
254
- break;
273
+
274
+ private async pollProgress(taskId: string) {
275
+ const client = this.agent.getPostHogClient();
276
+ if (!client) {
277
+ return;
278
+ }
279
+
280
+ const progress = await client.getTaskProgress(taskId);
281
+ if (progress.has_progress) {
282
+ this.updateProgressBar({
283
+ status: progress.status,
284
+ currentStep: progress.current_step,
285
+ completed: progress.completed_steps,
286
+ total: progress.total_steps,
287
+ });
255
288
  }
256
289
  }
257
290
  }
@@ -293,4 +326,4 @@ try {
293
326
  - **File I/O**: Efficient `.posthog/` folder management with minimal disk usage
294
327
  - **API Calls**: Cached PostHog task data to minimize network requests
295
328
  - **Event Streaming**: Real-time updates without blocking execution
296
- - **Template Processing**: Lazy-loaded templates with variable substitution
329
+ - **Template Processing**: Lazy-loaded templates with variable substitution
package/README.md CHANGED
@@ -15,17 +15,24 @@ bun run example
15
15
  - **PostHog Integration**: Fetches existing tasks from PostHog API
16
16
  - **Configurable Workflows**: Execute tasks via PostHog-defined or local workflows
17
17
  - **Branch Management**: Automatic branch creation for planning and implementation
18
- - **Event Streaming**: Real-time events for UI integration
18
+ - **Progress Tracking**: Execution status stored in PostHog `TaskProgress` records for easy polling
19
19
 
20
20
  ## Usage
21
21
 
22
22
  ```typescript
23
23
  import { Agent, PermissionMode } from '@posthog/agent';
24
+ import type { AgentEvent } from '@posthog/agent';
24
25
 
25
26
  const agent = new Agent({
26
27
  workingDirectory: "/path/to/repo",
27
28
  posthogApiUrl: "https://app.posthog.com",
28
- posthogApiKey: process.env.POSTHOG_API_KEY
29
+ posthogApiKey: process.env.POSTHOG_API_KEY, // Used for both API and MCP
30
+ onEvent: (event) => {
31
+ // Streamed updates for responsive UIs
32
+ if (event.type !== 'token') {
33
+ handleLiveEvent(event);
34
+ }
35
+ },
29
36
  });
30
37
 
31
38
  // Run by workflow
@@ -38,6 +45,15 @@ await agent.runWorkflow(taskId, workflowId, {
38
45
  });
39
46
  ```
40
47
 
48
+ For local MCP development:
49
+
50
+ ```typescript
51
+ const agent = new Agent({
52
+ workingDirectory: "/path/to/repo",
53
+ posthogMcpUrl: 'http://localhost:8787/mcp',
54
+ });
55
+ ```
56
+
41
57
  ## Workflow
42
58
 
43
59
  Each task execution creates Git branches:
@@ -78,22 +94,47 @@ your-repo/
78
94
  └── (your code)
79
95
  ```
80
96
 
81
- ## Array App Integration
97
+ ## Progress Updates
98
+
99
+ Progress for each task execution is persisted to PostHog's `TaskProgress` model, so UIs can poll for updates without relying on streaming hooks:
82
100
 
83
101
  ```typescript
84
- const result = await agent.runTask(taskId, userSelectedMode, {
85
- repositoryPath: selectedRepo,
86
- onEvent: (event) => {
87
- // Update UI based on event type
88
- switch (event.type) {
89
- case 'status': updateProgress(event.data); break;
90
- case 'file_write': showFileChange(event.data); break;
91
- case 'done': showCompletion(); break;
92
- }
93
- }
102
+ const agent = new Agent({
103
+ workingDirectory: repoPath,
104
+ posthogApiUrl: "https://app.posthog.com",
105
+ posthogApiKey: process.env.POSTHOG_KEY,
94
106
  });
107
+
108
+ const poller = setInterval(async () => {
109
+ const progress = await agent.getPostHogClient()?.getTaskProgress(taskId);
110
+ if (progress?.has_progress) {
111
+ renderProgress(progress.status, progress.current_step, progress.completed_steps, progress.total_steps);
112
+ }
113
+ }, 3000);
114
+
115
+ try {
116
+ await agent.runWorkflow(taskId, workflowId, { repositoryPath: repoPath });
117
+ } finally {
118
+ clearInterval(poller);
119
+ }
120
+
121
+ // Live stream still available through the onEvent hook
122
+ function handleLiveEvent(event: AgentEvent) {
123
+ switch (event.type) {
124
+ case 'status':
125
+ // optimistic UI update
126
+ break;
127
+ case 'error':
128
+ notifyError(event.message);
129
+ break;
130
+ default:
131
+ break;
132
+ }
133
+ }
95
134
  ```
96
135
 
136
+ > Prefer streaming updates? Pass an `onEvent` handler when constructing the agent to keep receiving real-time events while progress is also written to PostHog.
137
+
97
138
  ## Requirements
98
139
 
99
140
  - Bun runtime
@@ -139,4 +180,4 @@ await agent.runWorkflow(taskId, workflowId, {
139
180
  });
140
181
  ```
141
182
 
142
- Precedence for query options: base defaults in the SDK < global `queryOverrides` < per-stage `stageOverrides[stageKey].queryOverrides`.
183
+ Precedence for query options: base defaults in the SDK < global `queryOverrides` < per-stage `stageOverrides[stageKey].queryOverrides`.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { Agent, } from './src/agent.js';
2
2
  export { PermissionMode, } from './src/types.js';
3
- export type { Task, SupportingFile, ExecutionResult, AgentConfig } from './src/types.js';
3
+ export type { Task, SupportingFile, ExecutionResult, AgentConfig, McpServerConfig } from './src/types.js';
4
4
  export type { WorkflowDefinition, WorkflowStage, WorkflowExecutionOptions, AgentDefinition } from './src/workflow-types.js';
5
5
  export { Logger, LogLevel, } from './src/utils/logger.js';
6
6
  export type { LoggerConfig } from './src/utils/logger.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EACH,KAAK,GACR,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACH,cAAc,GACjB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACR,IAAI,EACJ,cAAc,EACd,eAAe,EACf,WAAW,EACd,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,kBAAkB,EAClB,aAAa,EACb,wBAAwB,EACxB,eAAe,EAChB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACH,MAAM,EACN,QAAQ,GACX,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACR,YAAY,EACf,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EACH,KAAK,GACR,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACH,cAAc,GACjB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACR,IAAI,EACJ,cAAc,EACd,eAAe,EACf,WAAW,EACX,eAAe,EAClB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,kBAAkB,EAClB,aAAa,EACb,wBAAwB,EACxB,eAAe,EAChB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACH,MAAM,EACN,QAAQ,GACX,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACR,YAAY,EACf,MAAM,uBAAuB,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import type { Task, ExecutionResult, AgentConfig } from './types.js';
2
2
  import type { WorkflowDefinition, WorkflowStage, WorkflowExecutionOptions } from './workflow-types.js';
3
+ import { PostHogAPIClient } from './posthog-api.js';
3
4
  export declare class Agent {
4
5
  private workingDirectory;
5
6
  private onEvent?;
@@ -13,6 +14,8 @@ export declare class Agent {
13
14
  private agentRegistry;
14
15
  private workflowRegistry;
15
16
  private stageExecutor;
17
+ private progressReporter;
18
+ private mcpServers?;
16
19
  debug: boolean;
17
20
  constructor(config?: AgentConfig);
18
21
  /**
@@ -31,6 +34,7 @@ export declare class Agent {
31
34
  queryOverrides?: Record<string, any>;
32
35
  }): Promise<ExecutionResult>;
33
36
  fetchTask(taskId: string): Promise<Task>;
37
+ getPostHogClient(): PostHogAPIClient | undefined;
34
38
  listTasks(filters?: {
35
39
  repository?: string;
36
40
  organization?: string;
@@ -48,7 +52,7 @@ export declare class Agent {
48
52
  createImplementationBranch(taskId: string, planningBranchName?: string): Promise<string>;
49
53
  commitImplementation(taskId: string, taskTitle: string, planSummary?: string): Promise<string>;
50
54
  createPullRequest(taskId: string, branchName: string, taskTitle: string, taskDescription: string): Promise<string>;
51
- attachPullRequestToTask(taskId: string, prUrl: string): Promise<void>;
55
+ attachPullRequestToTask(taskId: string, prUrl: string, branchName?: string): Promise<void>;
52
56
  updateTaskBranch(taskId: string, branchName: string): Promise<void>;
53
57
  cancelTask(taskId: string): void;
54
58
  getTaskExecutionStatus(taskId: string): string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/agent.ts"],"names":[],"mappings":"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"}
package/dist/src/agent.js CHANGED
@@ -10,6 +10,7 @@ import { AgentRegistry } from './agent-registry.js';
10
10
  import { WorkflowRegistry } from './workflow-registry.js';
11
11
  import { StageExecutor } from './stage-executor.js';
12
12
  import { PromptBuilder } from './prompt-builder.js';
13
+ import { TaskProgressReporter } from './task-progress-reporter.js';
13
14
  export { PermissionMode } from './types.js';
14
15
 
15
16
  class Agent {
@@ -25,11 +26,34 @@ class Agent {
25
26
  agentRegistry;
26
27
  workflowRegistry;
27
28
  stageExecutor;
29
+ progressReporter;
30
+ mcpServers;
28
31
  debug;
29
32
  constructor(config = {}) {
30
33
  this.workingDirectory = config.workingDirectory || process.cwd();
31
34
  this.onEvent = config.onEvent;
32
35
  this.debug = config.debug || false;
36
+ // Build default PostHog MCP server configuration
37
+ const posthogMcpUrl = config.posthogMcpUrl
38
+ || process.env.POSTHOG_MCP_URL
39
+ || 'https://mcp.posthog.com/mcp';
40
+ // Add auth if API key provided
41
+ const headers = {};
42
+ if (config.posthogApiKey) {
43
+ headers['Authorization'] = `Bearer ${config.posthogApiKey}`;
44
+ }
45
+ const defaultMcpServers = {
46
+ posthog: {
47
+ type: 'http',
48
+ url: posthogMcpUrl,
49
+ ...(Object.keys(headers).length > 0 ? { headers } : {}),
50
+ }
51
+ };
52
+ // Merge default PostHog MCP with user-provided servers (user config takes precedence)
53
+ this.mcpServers = {
54
+ ...defaultMcpServers,
55
+ ...config.mcpServers
56
+ };
33
57
  this.logger = new Logger({ debug: this.debug, prefix: '[PostHog Agent]' });
34
58
  this.taskManager = new TaskManager();
35
59
  this.eventTransformer = new EventTransformer();
@@ -53,7 +77,10 @@ class Agent {
53
77
  generatePlanTemplate: (vars) => this.templateManager.generatePlan(vars),
54
78
  logger: this.logger.child('PromptBuilder')
55
79
  });
56
- this.stageExecutor = new StageExecutor(this.agentRegistry, this.logger, promptBuilder);
80
+ this.stageExecutor = new StageExecutor(this.agentRegistry, this.logger, promptBuilder, undefined, // eventHandler set via setEventHandler below
81
+ this.mcpServers);
82
+ this.stageExecutor.setEventHandler((event) => this.emitEvent(event));
83
+ this.progressReporter = new TaskProgressReporter(this.posthogAPI, this.logger);
57
84
  }
58
85
  /**
59
86
  * Enable or disable debug logging
@@ -70,6 +97,7 @@ class Agent {
70
97
  if (!workflow) {
71
98
  throw new Error(`Workflow ${workflowId} not found`);
72
99
  }
100
+ const orderedStages = [...workflow.stages].sort((a, b) => a.position - b.position);
73
101
  // Ensure task is assigned to workflow and positioned at first stage
74
102
  if (this.posthogAPI) {
75
103
  try {
@@ -90,8 +118,12 @@ class Agent {
90
118
  const executionId = this.taskManager.generateExecutionId();
91
119
  this.logger.info('Starting workflow execution', { taskId: task.id, workflowId, executionId });
92
120
  this.taskManager.startExecution(task.id, 'plan_and_build', executionId);
121
+ await this.progressReporter.start(task.id, {
122
+ workflowId,
123
+ workflowRunId: executionId,
124
+ totalSteps: orderedStages.length,
125
+ });
93
126
  try {
94
- const orderedStages = [...workflow.stages].sort((a, b) => a.position - b.position);
95
127
  let startIndex = 0;
96
128
  const currentStageId = task.current_stage;
97
129
  // If task is already at the last stage, fail gracefully without progressing
@@ -99,7 +131,10 @@ class Agent {
99
131
  const currIdx = orderedStages.findIndex(s => s.id === currentStageId);
100
132
  const atLastStage = currIdx >= 0 && currIdx === orderedStages.length - 1;
101
133
  if (atLastStage) {
102
- this.emitEvent(this.eventTransformer.createStatusEvent('no_next_stage', { stage: orderedStages[currIdx].key }));
134
+ const finalStageKey = orderedStages[currIdx]?.key;
135
+ this.emitEvent(this.eventTransformer.createStatusEvent('no_next_stage', { stage: finalStageKey }));
136
+ await this.progressReporter.noNextStage(finalStageKey);
137
+ await this.progressReporter.complete();
103
138
  this.taskManager.completeExecution(executionId, { task, workflow });
104
139
  return { task, workflow };
105
140
  }
@@ -122,7 +157,9 @@ class Agent {
122
157
  }
123
158
  for (let i = startIndex; i < orderedStages.length; i++) {
124
159
  const stage = orderedStages[i];
160
+ await this.progressReporter.stageStarted(stage.key, i);
125
161
  await this.executeStage(task, stage, options);
162
+ await this.progressReporter.stageCompleted(stage.key, i + 1);
126
163
  if (options.autoProgress) {
127
164
  const hasNext = i < orderedStages.length - 1;
128
165
  if (hasNext) {
@@ -130,10 +167,12 @@ class Agent {
130
167
  }
131
168
  }
132
169
  }
170
+ await this.progressReporter.complete();
133
171
  this.taskManager.completeExecution(executionId, { task, workflow });
134
172
  return { task, workflow };
135
173
  }
136
174
  catch (error) {
175
+ await this.progressReporter.fail(error);
137
176
  this.taskManager.failExecution(executionId, error);
138
177
  throw error;
139
178
  }
@@ -153,17 +192,20 @@ class Agent {
153
192
  const planningBranch = await this.createPlanningBranch(task.id);
154
193
  await this.updateTaskBranch(task.id, planningBranch);
155
194
  this.emitEvent(this.eventTransformer.createStatusEvent('branch_created', { stage: stage.key, branch: planningBranch }));
195
+ await this.progressReporter.branchCreated(stage.key, planningBranch);
156
196
  }
157
197
  else if (!isPlanning && !isManual && shouldCreateImplBranch) {
158
198
  const implBranch = await this.createImplementationBranch(task.id);
159
199
  await this.updateTaskBranch(task.id, implBranch);
160
200
  this.emitEvent(this.eventTransformer.createStatusEvent('branch_created', { stage: stage.key, branch: implBranch }));
201
+ await this.progressReporter.branchCreated(stage.key, implBranch);
161
202
  }
162
203
  const result = await this.stageExecutor.execute(task, stage, options);
163
204
  if (result.plan) {
164
205
  await this.writePlan(task.id, result.plan);
165
206
  await this.commitPlan(task.id, task.title);
166
207
  this.emitEvent(this.eventTransformer.createStatusEvent('commit_made', { stage: stage.key, kind: 'plan' }));
208
+ await this.progressReporter.commitMade(stage.key, 'plan');
167
209
  }
168
210
  if (isManual) {
169
211
  const defaultOpenPR = true; // manual stages default to PR for review
@@ -177,12 +219,14 @@ class Agent {
177
219
  await this.updateTaskBranch(task.id, implBranch);
178
220
  branchName = implBranch;
179
221
  this.emitEvent(this.eventTransformer.createStatusEvent('branch_created', { stage: stage.key, branch: implBranch }));
222
+ await this.progressReporter.branchCreated(stage.key, implBranch);
180
223
  }
181
224
  try {
182
225
  const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
183
226
  await this.updateTaskBranch(task.id, branchName);
184
- await this.attachPullRequestToTask(task.id, prUrl);
227
+ await this.attachPullRequestToTask(task.id, prUrl, branchName);
185
228
  this.emitEvent(this.eventTransformer.createStatusEvent('pr_created', { stage: stage.key, prUrl }));
229
+ await this.progressReporter.pullRequestCreated(stage.key, prUrl);
186
230
  }
187
231
  catch { }
188
232
  }
@@ -195,6 +239,7 @@ class Agent {
195
239
  const planSummary = existingPlan ? existingPlan.split('\n')[0] : undefined;
196
240
  await this.commitImplementation(task.id, task.title, planSummary);
197
241
  this.emitEvent(this.eventTransformer.createStatusEvent('commit_made', { stage: stage.key, kind: 'implementation' }));
242
+ await this.progressReporter.commitMade(stage.key, 'implementation');
198
243
  }
199
244
  // PR creation on complete stage (or if explicitly requested), regardless of whether edits occurred
200
245
  {
@@ -205,8 +250,9 @@ class Agent {
205
250
  try {
206
251
  const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
207
252
  await this.updateTaskBranch(task.id, branchName);
208
- await this.attachPullRequestToTask(task.id, prUrl);
253
+ await this.attachPullRequestToTask(task.id, prUrl, branchName);
209
254
  this.emitEvent(this.eventTransformer.createStatusEvent('pr_created', { stage: stage.key, prUrl }));
255
+ await this.progressReporter.pullRequestCreated(stage.key, prUrl);
210
256
  }
211
257
  catch { }
212
258
  }
@@ -221,10 +267,11 @@ class Agent {
221
267
  // Direct prompt execution - still supported for low-level usage
222
268
  async run(prompt, options = {}) {
223
269
  const baseOptions = {
224
- model: "claude-4-5-sonnet",
270
+ model: "claude-sonnet-4-5-20250929",
225
271
  cwd: options.repositoryPath || this.workingDirectory,
226
272
  permissionMode: options.permissionMode || "default",
227
273
  settingSources: ["local"],
274
+ mcpServers: this.mcpServers,
228
275
  };
229
276
  const response = query({
230
277
  prompt,
@@ -232,7 +279,7 @@ class Agent {
232
279
  });
233
280
  const results = [];
234
281
  for await (const message of response) {
235
- this.logger.debug('Received message in direct run', { type: message.type });
282
+ this.logger.debug('Received message in direct run', message);
236
283
  const transformedEvent = this.eventTransformer.transform(message);
237
284
  this.onEvent?.(transformedEvent);
238
285
  results.push(message);
@@ -249,6 +296,9 @@ class Agent {
249
296
  }
250
297
  return this.posthogAPI.fetchTask(taskId);
251
298
  }
299
+ getPostHogClient() {
300
+ return this.posthogAPI;
301
+ }
252
302
  async listTasks(filters) {
253
303
  if (!this.posthogAPI) {
254
304
  throw new Error('PostHog API not configured. Provide posthogApiUrl and posthogApiKey in constructor.');
@@ -320,14 +370,14 @@ Generated by PostHog Agent`;
320
370
  this.logger.info('Pull request created', { taskId, prUrl });
321
371
  return prUrl;
322
372
  }
323
- async attachPullRequestToTask(taskId, prUrl) {
324
- this.logger.info('Attaching PR to task', { taskId, prUrl });
373
+ async attachPullRequestToTask(taskId, prUrl, branchName) {
374
+ this.logger.info('Attaching PR to task', { taskId, prUrl, branchName });
325
375
  if (!this.posthogAPI) {
326
376
  const error = new Error('PostHog API not configured. Cannot attach PR to task.');
327
377
  this.logger.error('PostHog API not configured', error);
328
378
  throw error;
329
379
  }
330
- await this.posthogAPI.updateTask(taskId, { github_pr_url: prUrl });
380
+ await this.posthogAPI.attachTaskPullRequest(taskId, prUrl, branchName);
331
381
  this.logger.debug('PR attached to task', { taskId, prUrl });
332
382
  }
333
383
  async updateTaskBranch(taskId, branchName) {
@@ -337,7 +387,7 @@ Generated by PostHog Agent`;
337
387
  this.logger.error('PostHog API not configured', error);
338
388
  throw error;
339
389
  }
340
- await this.posthogAPI.updateTask(taskId, { github_branch: branchName });
390
+ await this.posthogAPI.setTaskBranch(taskId, branchName);
341
391
  this.logger.debug('Task branch updated', { taskId, branchName });
342
392
  }
343
393
  // Execution management
@@ -364,6 +414,10 @@ Generated by PostHog Agent`;
364
414
  // Log all events except tokens (too verbose)
365
415
  this.logger.debug('Emitting event', { type: event.type, ts: event.ts });
366
416
  }
417
+ const persistPromise = this.progressReporter.recordEvent(event);
418
+ if (persistPromise && typeof persistPromise.then === 'function') {
419
+ persistPromise.catch((error) => this.logger.debug('Failed to persist agent event', { message: error.message }));
420
+ }
367
421
  this.onEvent?.(event);
368
422
  }
369
423
  }