@posthog/agent 1.0.2 → 1.2.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 (61) hide show
  1. package/CLAUDE.md +68 -35
  2. package/README.md +46 -14
  3. package/dist/index.js +4 -5
  4. package/dist/index.js.map +1 -1
  5. package/dist/src/agent-registry.js +4 -2
  6. package/dist/src/agent-registry.js.map +1 -1
  7. package/dist/src/agent.d.ts +4 -1
  8. package/dist/src/agent.d.ts.map +1 -1
  9. package/dist/src/agent.js +45 -14
  10. package/dist/src/agent.js.map +1 -1
  11. package/dist/src/agents/execution.js +4 -2
  12. package/dist/src/agents/execution.js.map +1 -1
  13. package/dist/src/agents/planning.js +4 -2
  14. package/dist/src/agents/planning.js.map +1 -1
  15. package/dist/src/event-transformer.d.ts +2 -0
  16. package/dist/src/event-transformer.d.ts.map +1 -1
  17. package/dist/src/event-transformer.js +57 -7
  18. package/dist/src/event-transformer.js.map +1 -1
  19. package/dist/src/file-manager.js +17 -14
  20. package/dist/src/file-manager.js.map +1 -1
  21. package/dist/src/git-manager.js +5 -2
  22. package/dist/src/git-manager.js.map +1 -1
  23. package/dist/src/posthog-api.d.ts +34 -0
  24. package/dist/src/posthog-api.d.ts.map +1 -1
  25. package/dist/src/posthog-api.js +42 -2
  26. package/dist/src/posthog-api.js.map +1 -1
  27. package/dist/src/prompt-builder.js +5 -2
  28. package/dist/src/prompt-builder.js.map +1 -1
  29. package/dist/src/stage-executor.d.ts +4 -2
  30. package/dist/src/stage-executor.d.ts.map +1 -1
  31. package/dist/src/stage-executor.js +22 -9
  32. package/dist/src/stage-executor.js.map +1 -1
  33. package/dist/src/task-manager.js +5 -2
  34. package/dist/src/task-manager.js.map +1 -1
  35. package/dist/src/task-progress-reporter.d.ts +44 -0
  36. package/dist/src/task-progress-reporter.d.ts.map +1 -0
  37. package/dist/src/task-progress-reporter.js +234 -0
  38. package/dist/src/task-progress-reporter.js.map +1 -0
  39. package/dist/src/template-manager.d.ts.map +1 -1
  40. package/dist/src/template-manager.js +16 -6
  41. package/dist/src/template-manager.js.map +1 -1
  42. package/dist/src/types.js +4 -2
  43. package/dist/src/types.js.map +1 -1
  44. package/dist/src/utils/logger.js +5 -3
  45. package/dist/src/utils/logger.js.map +1 -1
  46. package/dist/src/utils/mcp.js +4 -2
  47. package/dist/src/utils/mcp.js.map +1 -1
  48. package/dist/src/workflow-registry.js +4 -3
  49. package/dist/src/workflow-registry.js.map +1 -1
  50. package/dist/templates/plan-template.md +45 -0
  51. package/package.json +8 -2
  52. package/src/agent.ts +41 -8
  53. package/src/event-transformer.ts +61 -7
  54. package/src/posthog-api.ts +79 -0
  55. package/src/stage-executor.ts +24 -8
  56. package/src/task-progress-reporter.ts +287 -0
  57. package/src/template-manager.ts +11 -3
  58. package/dist/example.js +0 -49
  59. package/dist/example.js.map +0 -1
  60. package/dist/src/workflow-types.js +0 -2
  61. package/dist/src/workflow-types.js.map +0 -1
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,
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
@@ -78,22 +85,47 @@ your-repo/
78
85
  └── (your code)
79
86
  ```
80
87
 
81
- ## Array App Integration
88
+ ## Progress Updates
89
+
90
+ Progress for each task execution is persisted to PostHog's `TaskProgress` model, so UIs can poll for updates without relying on streaming hooks:
82
91
 
83
92
  ```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
- }
93
+ const agent = new Agent({
94
+ workingDirectory: repoPath,
95
+ posthogApiUrl: "https://app.posthog.com",
96
+ posthogApiKey: process.env.POSTHOG_KEY,
94
97
  });
98
+
99
+ const poller = setInterval(async () => {
100
+ const progress = await agent.getPostHogClient()?.getTaskProgress(taskId);
101
+ if (progress?.has_progress) {
102
+ renderProgress(progress.status, progress.current_step, progress.completed_steps, progress.total_steps);
103
+ }
104
+ }, 3000);
105
+
106
+ try {
107
+ await agent.runWorkflow(taskId, workflowId, { repositoryPath: repoPath });
108
+ } finally {
109
+ clearInterval(poller);
110
+ }
111
+
112
+ // Live stream still available through the onEvent hook
113
+ function handleLiveEvent(event: AgentEvent) {
114
+ switch (event.type) {
115
+ case 'status':
116
+ // optimistic UI update
117
+ break;
118
+ case 'error':
119
+ notifyError(event.message);
120
+ break;
121
+ default:
122
+ break;
123
+ }
124
+ }
95
125
  ```
96
126
 
127
+ > Prefer streaming updates? Pass an `onEvent` handler when constructing the agent to keep receiving real-time events while progress is also written to PostHog.
128
+
97
129
  ## Requirements
98
130
 
99
131
  - Bun runtime
@@ -139,4 +171,4 @@ await agent.runWorkflow(taskId, workflowId, {
139
171
  });
140
172
  ```
141
173
 
142
- Precedence for query options: base defaults in the SDK < global `queryOverrides` < per-stage `stageOverrides[stageKey].queryOverrides`.
174
+ Precedence for query options: base defaults in the SDK < global `queryOverrides` < per-stage `stageOverrides[stageKey].queryOverrides`.
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
- // Main entry point - re-exports from src
2
- export { Agent, } from './src/agent.js';
3
- export { PermissionMode, } from './src/types.js';
4
- export { Logger, LogLevel, } from './src/utils/logger.js';
5
- //# sourceMappingURL=index.js.map
1
+ export { Agent } from './src/agent.js';
2
+ export { PermissionMode } from './src/types.js';
3
+ export { LogLevel, Logger } from './src/utils/logger.js';
4
+ //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,OAAO,EACH,KAAK,GACR,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACH,cAAc,GACjB,MAAM,gBAAgB,CAAC;AAgBxB,OAAO,EACH,MAAM,EACN,QAAQ,GACX,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -1,4 +1,4 @@
1
- export class AgentRegistry {
1
+ class AgentRegistry {
2
2
  agentsByName = new Map();
3
3
  constructor(definitions) {
4
4
  if (definitions) {
@@ -51,4 +51,6 @@ export class AgentRegistry {
51
51
  return this.listAgents().map(({ id, name, agent_type, description }) => ({ id, name, agent_type, description }));
52
52
  }
53
53
  }
54
- //# sourceMappingURL=agent-registry.js.map
54
+
55
+ export { AgentRegistry };
56
+ //# sourceMappingURL=agent-registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-registry.js","sourceRoot":"","sources":["../../src/agent-registry.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,aAAa;IAChB,YAAY,GAAiC,IAAI,GAAG,EAAE,CAAC;IAE/D,YAAY,WAA+B;QACzC,IAAI,WAAW,EAAE,CAAC;YAChB,KAAK,MAAM,GAAG,IAAI,WAAW;gBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,KAAK,MAAM,GAAG,IAAI,aAAa,CAAC,gBAAgB,EAAE;gBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAED,MAAM,CAAC,gBAAgB;QACrB,OAAO;YACL;gBACE,EAAE,EAAE,gBAAgB;gBACpB,IAAI,EAAE,gBAAgB;gBACtB,UAAU,EAAE,UAAU;gBACtB,WAAW,EAAE,8CAA8C;aAC5D;YACD;gBACE,EAAE,EAAE,iBAAiB;gBACrB,IAAI,EAAE,iBAAiB;gBACvB,UAAU,EAAE,WAAW;gBACvB,WAAW,EAAE,0CAA0C;aACxD;YACD;gBACE,EAAE,EAAE,cAAc;gBAClB,IAAI,EAAE,cAAc;gBACpB,UAAU,EAAE,QAAQ;gBACpB,WAAW,EAAE,oCAAoC;aAClD;YACD;gBACE,EAAE,EAAE,eAAe;gBACnB,IAAI,EAAE,eAAe;gBACrB,UAAU,EAAE,SAAS;gBACrB,WAAW,EAAE,gCAAgC;aAC9C;SACF,CAAC;IACJ,CAAC;IAED,QAAQ,CAAC,GAAoB;QAC3B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,QAAQ,CAAC,IAAY;QACnB,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,UAAU;QACR,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,gBAAgB;QACd,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;IACnH,CAAC;CACF"}
1
+ {"version":3,"file":"agent-registry.js","sources":["../../src/agent-registry.ts"],"sourcesContent":["import type { AgentDefinition, AgentType } from './workflow-types.js';\n\nexport class AgentRegistry {\n private agentsByName: Map<string, AgentDefinition> = new Map();\n\n constructor(definitions?: AgentDefinition[]) {\n if (definitions) {\n for (const def of definitions) this.register(def);\n } else {\n for (const def of AgentRegistry.getDefaultAgents()) this.register(def);\n }\n }\n\n static getDefaultAgents(): AgentDefinition[] {\n return [\n {\n id: 'planning_basic',\n name: 'planning_basic',\n agent_type: 'planning',\n description: 'Analyze repo and produce implementation plan',\n },\n {\n id: 'code_generation',\n name: 'code_generation',\n agent_type: 'execution',\n description: 'Implements code changes using Claude SDK',\n },\n {\n id: 'review_basic',\n name: 'review_basic',\n agent_type: 'review',\n description: 'Reviews changes and suggests fixes',\n },\n {\n id: 'testing_basic',\n name: 'testing_basic',\n agent_type: 'testing',\n description: 'Runs tests and reports results',\n },\n ];\n }\n\n register(def: AgentDefinition): void {\n this.agentsByName.set(def.name, def);\n }\n\n getAgent(name: string): AgentDefinition | undefined {\n return this.agentsByName.get(name);\n }\n\n listAgents(): AgentDefinition[] {\n return Array.from(this.agentsByName.values());\n }\n\n exportForPostHog(): { id: string; name: string; agent_type: AgentType; description?: string }[] {\n return this.listAgents().map(({ id, name, agent_type, description }) => ({ id, name, agent_type, description }));\n }\n}\n\n"],"names":[],"mappings":"MAEa,aAAa,CAAA;AAChB,IAAA,YAAY,GAAiC,IAAI,GAAG,EAAE;AAE9D,IAAA,WAAA,CAAY,WAA+B,EAAA;QACzC,IAAI,WAAW,EAAE;YACf,KAAK,MAAM,GAAG,IAAI,WAAW;AAAE,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QACnD;aAAO;AACL,YAAA,KAAK,MAAM,GAAG,IAAI,aAAa,CAAC,gBAAgB,EAAE;AAAE,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QACxE;IACF;AAEA,IAAA,OAAO,gBAAgB,GAAA;QACrB,OAAO;AACL,YAAA;AACE,gBAAA,EAAE,EAAE,gBAAgB;AACpB,gBAAA,IAAI,EAAE,gBAAgB;AACtB,gBAAA,UAAU,EAAE,UAAU;AACtB,gBAAA,WAAW,EAAE,8CAA8C;AAC5D,aAAA;AACD,YAAA;AACE,gBAAA,EAAE,EAAE,iBAAiB;AACrB,gBAAA,IAAI,EAAE,iBAAiB;AACvB,gBAAA,UAAU,EAAE,WAAW;AACvB,gBAAA,WAAW,EAAE,0CAA0C;AACxD,aAAA;AACD,YAAA;AACE,gBAAA,EAAE,EAAE,cAAc;AAClB,gBAAA,IAAI,EAAE,cAAc;AACpB,gBAAA,UAAU,EAAE,QAAQ;AACpB,gBAAA,WAAW,EAAE,oCAAoC;AAClD,aAAA;AACD,YAAA;AACE,gBAAA,EAAE,EAAE,eAAe;AACnB,gBAAA,IAAI,EAAE,eAAe;AACrB,gBAAA,UAAU,EAAE,SAAS;AACrB,gBAAA,WAAW,EAAE,gCAAgC;AAC9C,aAAA;SACF;IACH;AAEA,IAAA,QAAQ,CAAC,GAAoB,EAAA;QAC3B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC;IACtC;AAEA,IAAA,QAAQ,CAAC,IAAY,EAAA;QACnB,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;IACpC;IAEA,UAAU,GAAA;QACR,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;IAC/C;IAEA,gBAAgB,GAAA;AACd,QAAA,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;IAClH;AACD;;;;"}
@@ -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,7 @@ export declare class Agent {
13
14
  private agentRegistry;
14
15
  private workflowRegistry;
15
16
  private stageExecutor;
17
+ private progressReporter;
16
18
  debug: boolean;
17
19
  constructor(config?: AgentConfig);
18
20
  /**
@@ -31,6 +33,7 @@ export declare class Agent {
31
33
  queryOverrides?: Record<string, any>;
32
34
  }): Promise<ExecutionResult>;
33
35
  fetchTask(taskId: string): Promise<Task>;
36
+ getPostHogClient(): PostHogAPIClient | undefined;
34
37
  listTasks(filters?: {
35
38
  repository?: string;
36
39
  organization?: string;
@@ -48,7 +51,7 @@ export declare class Agent {
48
51
  createImplementationBranch(taskId: string, planningBranchName?: string): Promise<string>;
49
52
  commitImplementation(taskId: string, taskTitle: string, planSummary?: string): Promise<string>;
50
53
  createPullRequest(taskId: string, branchName: string, taskTitle: string, taskDescription: string): Promise<string>;
51
- attachPullRequestToTask(taskId: string, prUrl: string): Promise<void>;
54
+ attachPullRequestToTask(taskId: string, prUrl: string, branchName?: string): Promise<void>;
52
55
  updateTaskBranch(taskId: string, branchName: string): Promise<void>;
53
56
  cancelTask(taskId: string): void;
54
57
  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
@@ -1,18 +1,19 @@
1
- import { query } from "@anthropic-ai/claude-agent-sdk";
1
+ import { query } from '@anthropic-ai/claude-agent-sdk';
2
2
  import { TaskManager } from './task-manager.js';
3
3
  import { PostHogAPIClient } from './posthog-api.js';
4
4
  import { PostHogFileManager } from './file-manager.js';
5
5
  import { GitManager } from './git-manager.js';
6
6
  import { TemplateManager } from './template-manager.js';
7
7
  import { EventTransformer } from './event-transformer.js';
8
- import { PLANNING_SYSTEM_PROMPT } from './agents/planning.js';
9
- import { EXECUTION_SYSTEM_PROMPT } from './agents/execution.js';
10
8
  import { Logger } from './utils/logger.js';
11
9
  import { AgentRegistry } from './agent-registry.js';
12
10
  import { WorkflowRegistry } from './workflow-registry.js';
13
11
  import { StageExecutor } from './stage-executor.js';
14
12
  import { PromptBuilder } from './prompt-builder.js';
15
- export class Agent {
13
+ import { TaskProgressReporter } from './task-progress-reporter.js';
14
+ export { PermissionMode } from './types.js';
15
+
16
+ class Agent {
16
17
  workingDirectory;
17
18
  onEvent;
18
19
  taskManager;
@@ -25,6 +26,7 @@ export class Agent {
25
26
  agentRegistry;
26
27
  workflowRegistry;
27
28
  stageExecutor;
29
+ progressReporter;
28
30
  debug;
29
31
  constructor(config = {}) {
30
32
  this.workingDirectory = config.workingDirectory || process.cwd();
@@ -54,6 +56,8 @@ export class Agent {
54
56
  logger: this.logger.child('PromptBuilder')
55
57
  });
56
58
  this.stageExecutor = new StageExecutor(this.agentRegistry, this.logger, promptBuilder);
59
+ this.stageExecutor.setEventHandler((event) => this.emitEvent(event));
60
+ this.progressReporter = new TaskProgressReporter(this.posthogAPI, this.logger);
57
61
  }
58
62
  /**
59
63
  * Enable or disable debug logging
@@ -70,6 +74,7 @@ export class Agent {
70
74
  if (!workflow) {
71
75
  throw new Error(`Workflow ${workflowId} not found`);
72
76
  }
77
+ const orderedStages = [...workflow.stages].sort((a, b) => a.position - b.position);
73
78
  // Ensure task is assigned to workflow and positioned at first stage
74
79
  if (this.posthogAPI) {
75
80
  try {
@@ -90,8 +95,12 @@ export class Agent {
90
95
  const executionId = this.taskManager.generateExecutionId();
91
96
  this.logger.info('Starting workflow execution', { taskId: task.id, workflowId, executionId });
92
97
  this.taskManager.startExecution(task.id, 'plan_and_build', executionId);
98
+ await this.progressReporter.start(task.id, {
99
+ workflowId,
100
+ workflowRunId: executionId,
101
+ totalSteps: orderedStages.length,
102
+ });
93
103
  try {
94
- const orderedStages = [...workflow.stages].sort((a, b) => a.position - b.position);
95
104
  let startIndex = 0;
96
105
  const currentStageId = task.current_stage;
97
106
  // If task is already at the last stage, fail gracefully without progressing
@@ -99,7 +108,10 @@ export class Agent {
99
108
  const currIdx = orderedStages.findIndex(s => s.id === currentStageId);
100
109
  const atLastStage = currIdx >= 0 && currIdx === orderedStages.length - 1;
101
110
  if (atLastStage) {
102
- this.emitEvent(this.eventTransformer.createStatusEvent('no_next_stage', { stage: orderedStages[currIdx].key }));
111
+ const finalStageKey = orderedStages[currIdx]?.key;
112
+ this.emitEvent(this.eventTransformer.createStatusEvent('no_next_stage', { stage: finalStageKey }));
113
+ await this.progressReporter.noNextStage(finalStageKey);
114
+ await this.progressReporter.complete();
103
115
  this.taskManager.completeExecution(executionId, { task, workflow });
104
116
  return { task, workflow };
105
117
  }
@@ -122,7 +134,9 @@ export class Agent {
122
134
  }
123
135
  for (let i = startIndex; i < orderedStages.length; i++) {
124
136
  const stage = orderedStages[i];
137
+ await this.progressReporter.stageStarted(stage.key, i);
125
138
  await this.executeStage(task, stage, options);
139
+ await this.progressReporter.stageCompleted(stage.key, i + 1);
126
140
  if (options.autoProgress) {
127
141
  const hasNext = i < orderedStages.length - 1;
128
142
  if (hasNext) {
@@ -130,10 +144,12 @@ export class Agent {
130
144
  }
131
145
  }
132
146
  }
147
+ await this.progressReporter.complete();
133
148
  this.taskManager.completeExecution(executionId, { task, workflow });
134
149
  return { task, workflow };
135
150
  }
136
151
  catch (error) {
152
+ await this.progressReporter.fail(error);
137
153
  this.taskManager.failExecution(executionId, error);
138
154
  throw error;
139
155
  }
@@ -153,17 +169,20 @@ export class Agent {
153
169
  const planningBranch = await this.createPlanningBranch(task.id);
154
170
  await this.updateTaskBranch(task.id, planningBranch);
155
171
  this.emitEvent(this.eventTransformer.createStatusEvent('branch_created', { stage: stage.key, branch: planningBranch }));
172
+ await this.progressReporter.branchCreated(stage.key, planningBranch);
156
173
  }
157
174
  else if (!isPlanning && !isManual && shouldCreateImplBranch) {
158
175
  const implBranch = await this.createImplementationBranch(task.id);
159
176
  await this.updateTaskBranch(task.id, implBranch);
160
177
  this.emitEvent(this.eventTransformer.createStatusEvent('branch_created', { stage: stage.key, branch: implBranch }));
178
+ await this.progressReporter.branchCreated(stage.key, implBranch);
161
179
  }
162
180
  const result = await this.stageExecutor.execute(task, stage, options);
163
181
  if (result.plan) {
164
182
  await this.writePlan(task.id, result.plan);
165
183
  await this.commitPlan(task.id, task.title);
166
184
  this.emitEvent(this.eventTransformer.createStatusEvent('commit_made', { stage: stage.key, kind: 'plan' }));
185
+ await this.progressReporter.commitMade(stage.key, 'plan');
167
186
  }
168
187
  if (isManual) {
169
188
  const defaultOpenPR = true; // manual stages default to PR for review
@@ -177,12 +196,14 @@ export class Agent {
177
196
  await this.updateTaskBranch(task.id, implBranch);
178
197
  branchName = implBranch;
179
198
  this.emitEvent(this.eventTransformer.createStatusEvent('branch_created', { stage: stage.key, branch: implBranch }));
199
+ await this.progressReporter.branchCreated(stage.key, implBranch);
180
200
  }
181
201
  try {
182
202
  const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
183
203
  await this.updateTaskBranch(task.id, branchName);
184
- await this.attachPullRequestToTask(task.id, prUrl);
204
+ await this.attachPullRequestToTask(task.id, prUrl, branchName);
185
205
  this.emitEvent(this.eventTransformer.createStatusEvent('pr_created', { stage: stage.key, prUrl }));
206
+ await this.progressReporter.pullRequestCreated(stage.key, prUrl);
186
207
  }
187
208
  catch { }
188
209
  }
@@ -195,6 +216,7 @@ export class Agent {
195
216
  const planSummary = existingPlan ? existingPlan.split('\n')[0] : undefined;
196
217
  await this.commitImplementation(task.id, task.title, planSummary);
197
218
  this.emitEvent(this.eventTransformer.createStatusEvent('commit_made', { stage: stage.key, kind: 'implementation' }));
219
+ await this.progressReporter.commitMade(stage.key, 'implementation');
198
220
  }
199
221
  // PR creation on complete stage (or if explicitly requested), regardless of whether edits occurred
200
222
  {
@@ -205,8 +227,9 @@ export class Agent {
205
227
  try {
206
228
  const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
207
229
  await this.updateTaskBranch(task.id, branchName);
208
- await this.attachPullRequestToTask(task.id, prUrl);
230
+ await this.attachPullRequestToTask(task.id, prUrl, branchName);
209
231
  this.emitEvent(this.eventTransformer.createStatusEvent('pr_created', { stage: stage.key, prUrl }));
232
+ await this.progressReporter.pullRequestCreated(stage.key, prUrl);
210
233
  }
211
234
  catch { }
212
235
  }
@@ -249,6 +272,9 @@ export class Agent {
249
272
  }
250
273
  return this.posthogAPI.fetchTask(taskId);
251
274
  }
275
+ getPostHogClient() {
276
+ return this.posthogAPI;
277
+ }
252
278
  async listTasks(filters) {
253
279
  if (!this.posthogAPI) {
254
280
  throw new Error('PostHog API not configured. Provide posthogApiUrl and posthogApiKey in constructor.');
@@ -320,14 +346,14 @@ Generated by PostHog Agent`;
320
346
  this.logger.info('Pull request created', { taskId, prUrl });
321
347
  return prUrl;
322
348
  }
323
- async attachPullRequestToTask(taskId, prUrl) {
324
- this.logger.info('Attaching PR to task', { taskId, prUrl });
349
+ async attachPullRequestToTask(taskId, prUrl, branchName) {
350
+ this.logger.info('Attaching PR to task', { taskId, prUrl, branchName });
325
351
  if (!this.posthogAPI) {
326
352
  const error = new Error('PostHog API not configured. Cannot attach PR to task.');
327
353
  this.logger.error('PostHog API not configured', error);
328
354
  throw error;
329
355
  }
330
- await this.posthogAPI.updateTask(taskId, { github_pr_url: prUrl });
356
+ await this.posthogAPI.attachTaskPullRequest(taskId, prUrl, branchName);
331
357
  this.logger.debug('PR attached to task', { taskId, prUrl });
332
358
  }
333
359
  async updateTaskBranch(taskId, branchName) {
@@ -337,7 +363,7 @@ Generated by PostHog Agent`;
337
363
  this.logger.error('PostHog API not configured', error);
338
364
  throw error;
339
365
  }
340
- await this.posthogAPI.updateTask(taskId, { github_branch: branchName });
366
+ await this.posthogAPI.setTaskBranch(taskId, branchName);
341
367
  this.logger.debug('Task branch updated', { taskId, branchName });
342
368
  }
343
369
  // Execution management
@@ -364,8 +390,13 @@ Generated by PostHog Agent`;
364
390
  // Log all events except tokens (too verbose)
365
391
  this.logger.debug('Emitting event', { type: event.type, ts: event.ts });
366
392
  }
393
+ const persistPromise = this.progressReporter.recordEvent(event);
394
+ if (persistPromise && typeof persistPromise.then === 'function') {
395
+ persistPromise.catch((error) => this.logger.debug('Failed to persist agent event', { message: error.message }));
396
+ }
367
397
  this.onEvent?.(event);
368
398
  }
369
399
  }
370
- export { PermissionMode } from './types.js';
371
- //# sourceMappingURL=agent.js.map
400
+
401
+ export { Agent };
402
+ //# sourceMappingURL=agent.js.map