@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,203 +1,222 @@
1
- import { query } from '@anthropic-ai/claude-agent-sdk';
2
- import { RESEARCH_SYSTEM_PROMPT } from '../../agents/research.js';
3
- import type { WorkflowStepRunner } from '../types.js';
4
- import type { ResearchEvaluation } from '../../types.js';
5
- import { finalizeStepGitActions } from '../utils.js';
1
+ import { query } from "@anthropic-ai/claude-agent-sdk";
2
+ import { RESEARCH_SYSTEM_PROMPT } from "../../agents/research.js";
3
+ import type { ResearchEvaluation } from "../../types.js";
4
+ import type { WorkflowStepRunner } from "../types.js";
5
+ import { finalizeStepGitActions } from "../utils.js";
6
6
 
7
7
  export const researchStep: WorkflowStepRunner = async ({ step, context }) => {
8
- const {
9
- task,
10
- cwd,
11
- isCloudMode,
12
- options,
13
- logger,
14
- fileManager,
15
- gitManager,
16
- promptBuilder,
17
- adapter,
18
- mcpServers,
19
- emitEvent,
20
- } = context;
21
-
22
- const stepLogger = logger.child('ResearchStep');
23
-
24
- const existingResearch = await fileManager.readResearch(task.id);
25
- if (existingResearch) {
26
- stepLogger.info('Research already exists', { taskId: task.id, hasQuestions: !!existingResearch.questions, answered: existingResearch.answered });
27
-
28
- // If there are unanswered questions, re-emit them so UI can prompt user
29
- if (existingResearch.questions && !existingResearch.answered) {
30
- stepLogger.info('Re-emitting unanswered research questions', {
31
- taskId: task.id,
32
- questionCount: existingResearch.questions.length
33
- });
34
-
35
- emitEvent({
36
- type: 'artifact',
37
- ts: Date.now(),
38
- kind: 'research_questions',
39
- content: existingResearch.questions,
40
- });
41
-
42
- // In local mode, halt to allow user to answer
43
- if (!isCloudMode) {
44
- emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
45
- return { status: 'skipped', halt: true };
46
- }
47
- }
48
-
49
- return { status: 'skipped' };
50
- }
51
-
52
- stepLogger.info('Starting research phase', { taskId: task.id });
53
- emitEvent(adapter.createStatusEvent('phase_start', { phase: 'research' }));
54
-
55
- const researchPrompt = await promptBuilder.buildResearchPrompt(task, cwd);
56
- const fullPrompt = `${RESEARCH_SYSTEM_PROMPT}\n\n${researchPrompt}`;
57
-
58
- const baseOptions: Record<string, any> = {
59
- model: step.model,
60
- cwd,
61
- permissionMode: 'plan',
62
- settingSources: ['local'],
63
- mcpServers,
64
- // Allow research tools: read-only operations, web search, and MCP resources
65
- allowedTools: [
66
- 'Read',
67
- 'Glob',
68
- 'Grep',
69
- 'WebFetch',
70
- 'WebSearch',
71
- 'ListMcpResources',
72
- 'ReadMcpResource',
73
- 'TodoWrite',
74
- 'BashOutput',
75
- ],
76
- };
77
-
78
- const response = query({
79
- prompt: fullPrompt,
80
- options: { ...baseOptions, ...(options.queryOverrides || {}) },
8
+ const {
9
+ task,
10
+ cwd,
11
+ isCloudMode,
12
+ options,
13
+ logger,
14
+ fileManager,
15
+ gitManager,
16
+ promptBuilder,
17
+ adapter,
18
+ mcpServers,
19
+ emitEvent,
20
+ } = context;
21
+
22
+ const stepLogger = logger.child("ResearchStep");
23
+
24
+ const existingResearch = await fileManager.readResearch(task.id);
25
+ if (existingResearch) {
26
+ stepLogger.info("Research already exists", {
27
+ taskId: task.id,
28
+ hasQuestions: !!existingResearch.questions,
29
+ answered: existingResearch.answered,
81
30
  });
82
31
 
83
- let jsonContent = '';
84
- for await (const message of response) {
85
- emitEvent(adapter.createRawSDKEvent(message));
86
- const transformedEvents = adapter.transform(message);
87
- for (const event of transformedEvents) {
88
- emitEvent(event);
89
- }
90
- if (message.type === 'assistant' && message.message?.content) {
91
- for (const c of message.message.content) {
92
- if (c.type === 'text' && c.text) {
93
- jsonContent += c.text;
94
- }
95
- }
96
- }
97
- }
32
+ // If there are unanswered questions, re-emit them so UI can prompt user
33
+ if (existingResearch.questions && !existingResearch.answered) {
34
+ stepLogger.info("Re-emitting unanswered research questions", {
35
+ taskId: task.id,
36
+ questionCount: existingResearch.questions.length,
37
+ });
98
38
 
99
- if (!jsonContent.trim()) {
100
- stepLogger.error('No JSON output from research agent', { taskId: task.id });
101
- emitEvent({
102
- type: 'error',
103
- ts: Date.now(),
104
- message: 'Research agent returned no output',
105
- });
106
- return { status: 'completed', halt: true };
39
+ emitEvent({
40
+ type: "artifact",
41
+ ts: Date.now(),
42
+ kind: "research_questions",
43
+ content: existingResearch.questions,
44
+ });
45
+
46
+ // In local mode, halt to allow user to answer
47
+ if (!isCloudMode) {
48
+ emitEvent(
49
+ adapter.createStatusEvent("phase_complete", { phase: "research" }),
50
+ );
51
+ return { status: "skipped", halt: true };
52
+ }
107
53
  }
108
54
 
109
- // Parse JSON response
110
- let evaluation: ResearchEvaluation;
111
- try {
112
- // Extract JSON from potential markdown code blocks or other wrapping
113
- const jsonMatch = jsonContent.match(/\{[\s\S]*\}/);
114
- if (!jsonMatch) {
115
- throw new Error('No JSON object found in response');
55
+ return { status: "skipped" };
56
+ }
57
+
58
+ stepLogger.info("Starting research phase", { taskId: task.id });
59
+ emitEvent(adapter.createStatusEvent("phase_start", { phase: "research" }));
60
+
61
+ const researchPrompt = await promptBuilder.buildResearchPrompt(task, cwd);
62
+ const fullPrompt = `${RESEARCH_SYSTEM_PROMPT}\n\n${researchPrompt}`;
63
+
64
+ const baseOptions: Record<string, unknown> = {
65
+ model: step.model,
66
+ cwd,
67
+ permissionMode: "plan",
68
+ settingSources: ["local"],
69
+ mcpServers,
70
+ // Allow research tools: read-only operations, web search, and MCP resources
71
+ allowedTools: [
72
+ "Read",
73
+ "Glob",
74
+ "Grep",
75
+ "WebFetch",
76
+ "WebSearch",
77
+ "ListMcpResources",
78
+ "ReadMcpResource",
79
+ "TodoWrite",
80
+ "BashOutput",
81
+ ],
82
+ };
83
+
84
+ const response = query({
85
+ prompt: fullPrompt,
86
+ options: { ...baseOptions, ...(options.queryOverrides || {}) },
87
+ });
88
+
89
+ let jsonContent = "";
90
+ try {
91
+ for await (const message of response) {
92
+ emitEvent(adapter.createRawSDKEvent(message));
93
+ const transformedEvents = adapter.transform(message);
94
+ for (const event of transformedEvents) {
95
+ emitEvent(event);
96
+ }
97
+ if (message.type === "assistant" && message.message?.content) {
98
+ for (const c of message.message.content) {
99
+ if (c.type === "text" && c.text) {
100
+ jsonContent += c.text;
101
+ }
116
102
  }
117
- evaluation = JSON.parse(jsonMatch[0]);
118
- stepLogger.info('Parsed research evaluation', {
119
- taskId: task.id,
120
- score: evaluation.actionabilityScore,
121
- hasQuestions: !!evaluation.questions,
122
- });
123
- } catch (error) {
124
- stepLogger.error('Failed to parse research JSON', {
125
- taskId: task.id,
126
- error: error instanceof Error ? error.message : String(error),
127
- content: jsonContent.substring(0, 500),
128
- });
129
- emitEvent({
130
- type: 'error',
131
- ts: Date.now(),
132
- message: `Failed to parse research JSON: ${
133
- error instanceof Error ? error.message : String(error)
134
- }`,
135
- });
136
- return { status: 'completed', halt: true };
103
+ }
137
104
  }
105
+ } catch (error) {
106
+ stepLogger.error("Error during research step query", error);
107
+ throw error;
108
+ }
138
109
 
139
- // Add answered/answers fields to evaluation
140
- if (evaluation.questions && evaluation.questions.length > 0) {
141
- evaluation.answered = false;
142
- evaluation.answers = undefined;
110
+ if (!jsonContent.trim()) {
111
+ stepLogger.error("No JSON output from research agent", { taskId: task.id });
112
+ emitEvent({
113
+ type: "error",
114
+ ts: Date.now(),
115
+ message: "Research agent returned no output",
116
+ });
117
+ return { status: "completed", halt: true };
118
+ }
119
+
120
+ // Parse JSON response
121
+ let evaluation: ResearchEvaluation;
122
+ try {
123
+ // Extract JSON from potential markdown code blocks or other wrapping
124
+ const jsonMatch = jsonContent.match(/\{[\s\S]*\}/);
125
+ if (!jsonMatch) {
126
+ throw new Error("No JSON object found in response");
143
127
  }
144
-
145
- // Always write research.json
146
- await fileManager.writeResearch(task.id, evaluation);
147
- stepLogger.info('Research evaluation written', {
148
- taskId: task.id,
149
- score: evaluation.actionabilityScore,
150
- hasQuestions: !!evaluation.questions,
128
+ evaluation = JSON.parse(jsonMatch[0]);
129
+ stepLogger.info("Parsed research evaluation", {
130
+ taskId: task.id,
131
+ score: evaluation.actionabilityScore,
132
+ hasQuestions: !!evaluation.questions,
133
+ });
134
+ } catch (error) {
135
+ stepLogger.error("Failed to parse research JSON", {
136
+ taskId: task.id,
137
+ error: error instanceof Error ? error.message : String(error),
138
+ content: jsonContent.substring(0, 500),
151
139
  });
152
-
153
140
  emitEvent({
154
- type: 'artifact',
155
- ts: Date.now(),
156
- kind: 'research_evaluation',
157
- content: evaluation,
141
+ type: "error",
142
+ ts: Date.now(),
143
+ message: `Failed to parse research JSON: ${
144
+ error instanceof Error ? error.message : String(error)
145
+ }`,
158
146
  });
159
-
160
- await gitManager.addAllPostHogFiles();
161
- await finalizeStepGitActions(context, step, {
162
- commitMessage: `Research phase for ${task.title}`,
147
+ return { status: "completed", halt: true };
148
+ }
149
+
150
+ // Add answered/answers fields to evaluation
151
+ if (evaluation.questions && evaluation.questions.length > 0) {
152
+ evaluation.answered = false;
153
+ evaluation.answers = undefined;
154
+ }
155
+
156
+ // Always write research.json
157
+ await fileManager.writeResearch(task.id, evaluation);
158
+ stepLogger.info("Research evaluation written", {
159
+ taskId: task.id,
160
+ score: evaluation.actionabilityScore,
161
+ hasQuestions: !!evaluation.questions,
162
+ });
163
+
164
+ emitEvent({
165
+ type: "artifact",
166
+ ts: Date.now(),
167
+ kind: "research_evaluation",
168
+ content: evaluation,
169
+ });
170
+
171
+ await gitManager.addAllPostHogFiles();
172
+ await finalizeStepGitActions(context, step, {
173
+ commitMessage: `Research phase for ${task.title}`,
174
+ });
175
+
176
+ // Log whether questions need answering
177
+ if (
178
+ evaluation.actionabilityScore < 0.7 &&
179
+ evaluation.questions &&
180
+ evaluation.questions.length > 0
181
+ ) {
182
+ stepLogger.info("Actionability score below threshold, questions needed", {
183
+ taskId: task.id,
184
+ score: evaluation.actionabilityScore,
185
+ questionCount: evaluation.questions.length,
163
186
  });
164
187
 
165
- // Log whether questions need answering
166
- if (evaluation.actionabilityScore < 0.7 && evaluation.questions && evaluation.questions.length > 0) {
167
- stepLogger.info('Actionability score below threshold, questions needed', {
168
- taskId: task.id,
169
- score: evaluation.actionabilityScore,
170
- questionCount: evaluation.questions.length,
171
- });
172
-
173
- emitEvent({
174
- type: 'artifact',
175
- ts: Date.now(),
176
- kind: 'research_questions',
177
- content: evaluation.questions,
178
- });
179
- } else {
180
- stepLogger.info('Actionability score acceptable, proceeding to planning', {
181
- taskId: task.id,
182
- score: evaluation.actionabilityScore,
183
- });
184
- }
185
-
186
- // In local mode, always halt after research for user review
187
- if (!isCloudMode) {
188
- emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
189
- return { status: 'completed', halt: true };
190
- }
191
-
192
- // In cloud mode, check if questions need answering
193
- const researchData = await fileManager.readResearch(task.id);
194
- if (researchData?.questions && !researchData.answered) {
195
- // Questions need answering - halt for user input in cloud mode too
196
- emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
197
- return { status: 'completed', halt: true };
198
- }
199
-
200
- // No questions or questions already answered - proceed to planning
201
- emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
202
- return { status: 'completed' };
188
+ emitEvent({
189
+ type: "artifact",
190
+ ts: Date.now(),
191
+ kind: "research_questions",
192
+ content: evaluation.questions,
193
+ });
194
+ } else {
195
+ stepLogger.info("Actionability score acceptable, proceeding to planning", {
196
+ taskId: task.id,
197
+ score: evaluation.actionabilityScore,
198
+ });
199
+ }
200
+
201
+ // In local mode, always halt after research for user review
202
+ if (!isCloudMode) {
203
+ emitEvent(
204
+ adapter.createStatusEvent("phase_complete", { phase: "research" }),
205
+ );
206
+ return { status: "completed", halt: true };
207
+ }
208
+
209
+ // In cloud mode, check if questions need answering
210
+ const researchData = await fileManager.readResearch(task.id);
211
+ if (researchData?.questions && !researchData.answered) {
212
+ // Questions need answering - halt for user input in cloud mode too
213
+ emitEvent(
214
+ adapter.createStatusEvent("phase_complete", { phase: "research" }),
215
+ );
216
+ return { status: "completed", halt: true };
217
+ }
218
+
219
+ // No questions or questions already answered - proceed to planning
220
+ emitEvent(adapter.createStatusEvent("phase_complete", { phase: "research" }));
221
+ return { status: "completed" };
203
222
  };
@@ -1,51 +1,53 @@
1
- import type { Task, TaskExecutionOptions, PermissionMode } from '../types.js';
2
- import type { Logger } from '../utils/logger.js';
3
- import type { PostHogFileManager } from '../file-manager.js';
4
- import type { GitManager } from '../git-manager.js';
5
- import type { PromptBuilder } from '../prompt-builder.js';
6
- import type { TaskProgressReporter } from '../task-progress-reporter.js';
7
- import type { ProviderAdapter } from '../adapters/types.js';
8
- import type { PostHogAPIClient } from '../posthog-api.js';
1
+ import type { ProviderAdapter } from "../adapters/types.js";
2
+ import type { PostHogFileManager } from "../file-manager.js";
3
+ import type { GitManager } from "../git-manager.js";
4
+ import type { PostHogAPIClient } from "../posthog-api.js";
5
+ import type { PromptBuilder } from "../prompt-builder.js";
6
+ import type { TaskProgressReporter } from "../task-progress-reporter.js";
7
+ import type { PermissionMode, Task, TaskExecutionOptions } from "../types.js";
8
+ import type { Logger } from "../utils/logger.js";
9
9
 
10
10
  export interface WorkflowRuntime {
11
- task: Task;
12
- taskSlug: string;
13
- cwd: string;
14
- isCloudMode: boolean;
15
- options: TaskExecutionOptions;
16
- logger: Logger;
17
- fileManager: PostHogFileManager;
18
- gitManager: GitManager;
19
- promptBuilder: PromptBuilder;
20
- progressReporter: TaskProgressReporter;
21
- adapter: ProviderAdapter;
22
- mcpServers?: Record<string, any>;
23
- posthogAPI?: PostHogAPIClient;
24
- emitEvent: (event: any) => void;
25
- stepResults: Record<string, any>;
11
+ task: Task;
12
+ taskSlug: string;
13
+ cwd: string;
14
+ isCloudMode: boolean;
15
+ options: TaskExecutionOptions;
16
+ logger: Logger;
17
+ fileManager: PostHogFileManager;
18
+ gitManager: GitManager;
19
+ promptBuilder: PromptBuilder;
20
+ progressReporter: TaskProgressReporter;
21
+ adapter: ProviderAdapter;
22
+ mcpServers?: Record<string, unknown>;
23
+ posthogAPI?: PostHogAPIClient;
24
+ emitEvent: (event: unknown) => void;
25
+ stepResults: Record<string, unknown>;
26
26
  }
27
27
 
28
28
  export interface WorkflowStepDefinition {
29
- id: string;
30
- name: string;
31
- agent: string;
32
- model: string;
33
- permissionMode?: PermissionMode | string;
34
- commit?: boolean;
35
- push?: boolean;
36
- run: WorkflowStepRunner;
29
+ id: string;
30
+ name: string;
31
+ agent: string;
32
+ model: string;
33
+ permissionMode?: PermissionMode | string;
34
+ commit?: boolean;
35
+ push?: boolean;
36
+ run: WorkflowStepRunner;
37
37
  }
38
38
 
39
39
  export interface WorkflowStepRuntime {
40
- step: WorkflowStepDefinition;
41
- context: WorkflowRuntime;
40
+ step: WorkflowStepDefinition;
41
+ context: WorkflowRuntime;
42
42
  }
43
43
 
44
44
  export interface WorkflowStepResult {
45
- status: 'completed' | 'skipped';
46
- halt?: boolean;
45
+ status: "completed" | "skipped";
46
+ halt?: boolean;
47
47
  }
48
48
 
49
- export type WorkflowStepRunner = (runtime: WorkflowStepRuntime) => Promise<WorkflowStepResult>;
49
+ export type WorkflowStepRunner = (
50
+ runtime: WorkflowStepRuntime,
51
+ ) => Promise<WorkflowStepResult>;
50
52
 
51
53
  export type WorkflowDefinition = WorkflowStepDefinition[];
@@ -1,8 +1,8 @@
1
- import type { WorkflowRuntime, WorkflowStepDefinition } from './types.js';
1
+ import type { WorkflowRuntime, WorkflowStepDefinition } from "./types.js";
2
2
 
3
3
  interface FinalizeGitOptions {
4
- commitMessage: string;
5
- allowEmptyCommit?: boolean;
4
+ commitMessage: string;
5
+ allowEmptyCommit?: boolean;
6
6
  }
7
7
 
8
8
  /**
@@ -10,41 +10,44 @@ interface FinalizeGitOptions {
10
10
  * Returns true if a commit was created.
11
11
  */
12
12
  export async function finalizeStepGitActions(
13
- context: WorkflowRuntime,
14
- step: WorkflowStepDefinition,
15
- options: FinalizeGitOptions
13
+ context: WorkflowRuntime,
14
+ step: WorkflowStepDefinition,
15
+ options: FinalizeGitOptions,
16
16
  ): Promise<boolean> {
17
- if (!step.commit) {
18
- return false;
19
- }
17
+ if (!step.commit) {
18
+ return false;
19
+ }
20
20
 
21
- const { gitManager, logger } = context;
22
- const hasStagedChanges = await gitManager.hasStagedChanges();
21
+ const { gitManager, logger } = context;
22
+ const hasStagedChanges = await gitManager.hasStagedChanges();
23
23
 
24
- if (!hasStagedChanges && !options.allowEmptyCommit) {
25
- logger.debug('No staged changes to commit for step', { stepId: step.id });
26
- return false;
27
- }
24
+ if (!hasStagedChanges && !options.allowEmptyCommit) {
25
+ logger.debug("No staged changes to commit for step", { stepId: step.id });
26
+ return false;
27
+ }
28
28
 
29
- try {
30
- await gitManager.commitChanges(options.commitMessage);
31
- logger.info('Committed changes for step', {
32
- stepId: step.id,
33
- message: options.commitMessage,
34
- });
35
- } catch (error) {
36
- logger.error('Failed to commit changes for step', {
37
- stepId: step.id,
38
- error: error instanceof Error ? error.message : String(error),
39
- });
40
- throw error;
41
- }
29
+ try {
30
+ await gitManager.commitChanges(options.commitMessage);
31
+ logger.info("Committed changes for step", {
32
+ stepId: step.id,
33
+ message: options.commitMessage,
34
+ });
35
+ } catch (error) {
36
+ logger.error("Failed to commit changes for step", {
37
+ stepId: step.id,
38
+ error: error instanceof Error ? error.message : String(error),
39
+ });
40
+ throw error;
41
+ }
42
42
 
43
- if (step.push) {
44
- const branchName = await gitManager.getCurrentBranch();
45
- await gitManager.pushBranch(branchName);
46
- logger.info('Pushed branch after step', { stepId: step.id, branch: branchName });
47
- }
43
+ if (step.push) {
44
+ const branchName = await gitManager.getCurrentBranch();
45
+ await gitManager.pushBranch(branchName);
46
+ logger.info("Pushed branch after step", {
47
+ stepId: step.id,
48
+ branch: branchName,
49
+ });
50
+ }
48
51
 
49
- return true;
52
+ return true;
50
53
  }
package/LICENSE DELETED
@@ -1,33 +0,0 @@
1
- Business Source License 1.1
2
-
3
- Parameters
4
-
5
- Licensor: PostHog Inc.
6
- Licensed Work: Array & Posthog Agent package
7
- The Licensed Work is © 2025 PostHog Inc.
8
-
9
- Change Date: None (the Licensed Work will remain under this License indefinitely unless Licensor specifies otherwise)
10
- Change License: At Licensor's discretion
11
-
12
- Additional Use Grant:
13
- You may use, modify, and self-host this software for personal purposes.
14
- You may also submit contributions (e.g., pull requests) to the Licensed Work under this License.
15
- Commercial redistribution, resale, or offering as a managed/hosted service requires a separate commercial agreement with the Licensor.
16
- Using the Licensed Work to build or offer a competing product or service is prohibited without explicit written permission from the Licensor.
17
-
18
- Terms
19
-
20
- The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make use of the Licensed Work for personal purposes. The Licensor may make an Additional Use Grant, above, permitting limited production use.
21
-
22
- Effective on the Change Date (if one is ever designated by the Licensor), the Change License will apply to the Licensed Work.
23
-
24
- Any use of the Licensed Work not explicitly permitted by this License is prohibited.
25
- This License applies separately to each version of the Licensed Work released by the Licensor.
26
-
27
- THE LICENSED WORK IS PROVIDED "AS IS". THE LICENSOR MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
28
-
29
- This License does not grant trademark rights, and no license is granted for use of the Licensor's trademarks, trade names, or logos.
30
-
31
- License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
32
-
33
- "Business Source License" is a trademark of MariaDB Corporation Ab.