@posthog/agent 1.24.0 → 1.24.2

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 (116) hide show
  1. package/LICENSE +33 -0
  2. package/dist/index.d.ts +11 -11
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -3
  5. package/dist/src/adapters/claude/claude-adapter.d.ts +3 -3
  6. package/dist/src/adapters/claude/claude-adapter.d.ts.map +1 -1
  7. package/dist/src/adapters/claude/claude-adapter.js +111 -156
  8. package/dist/src/adapters/claude/claude-adapter.js.map +1 -1
  9. package/dist/src/adapters/claude/tool-mapper.d.ts +1 -1
  10. package/dist/src/adapters/claude/tool-mapper.d.ts.map +1 -1
  11. package/dist/src/adapters/claude/tool-mapper.js.map +1 -1
  12. package/dist/src/adapters/types.d.ts +1 -1
  13. package/dist/src/adapters/types.d.ts.map +1 -1
  14. package/dist/src/agent.d.ts +7 -7
  15. package/dist/src/agent.d.ts.map +1 -1
  16. package/dist/src/agent.js +85 -143
  17. package/dist/src/agent.js.map +1 -1
  18. package/dist/src/agents/execution.js.map +1 -1
  19. package/dist/src/agents/planning.js.map +1 -1
  20. package/dist/src/agents/research.js.map +1 -1
  21. package/dist/src/file-manager.d.ts +4 -4
  22. package/dist/src/file-manager.d.ts.map +1 -1
  23. package/dist/src/file-manager.js +58 -59
  24. package/dist/src/file-manager.js.map +1 -1
  25. package/dist/src/git-manager.d.ts +1 -1
  26. package/dist/src/git-manager.d.ts.map +1 -1
  27. package/dist/src/git-manager.js +70 -87
  28. package/dist/src/git-manager.js.map +1 -1
  29. package/dist/src/posthog-api.d.ts +3 -2
  30. package/dist/src/posthog-api.d.ts.map +1 -1
  31. package/dist/src/posthog-api.js +22 -22
  32. package/dist/src/posthog-api.js.map +1 -1
  33. package/dist/src/prompt-builder.d.ts +3 -3
  34. package/dist/src/prompt-builder.d.ts.map +1 -1
  35. package/dist/src/prompt-builder.js +93 -123
  36. package/dist/src/prompt-builder.js.map +1 -1
  37. package/dist/src/task-manager.d.ts +4 -4
  38. package/dist/src/task-manager.d.ts.map +1 -1
  39. package/dist/src/task-manager.js +18 -19
  40. package/dist/src/task-manager.js.map +1 -1
  41. package/dist/src/task-progress-reporter.d.ts +4 -3
  42. package/dist/src/task-progress-reporter.d.ts.map +1 -1
  43. package/dist/src/task-progress-reporter.js +54 -59
  44. package/dist/src/task-progress-reporter.js.map +1 -1
  45. package/dist/src/template-manager.d.ts +1 -1
  46. package/dist/src/template-manager.d.ts.map +1 -1
  47. package/dist/src/template-manager.js +28 -30
  48. package/dist/src/template-manager.js.map +1 -1
  49. package/dist/src/todo-manager.d.ts +3 -3
  50. package/dist/src/todo-manager.d.ts.map +1 -1
  51. package/dist/src/todo-manager.js +24 -29
  52. package/dist/src/todo-manager.js.map +1 -1
  53. package/dist/src/tools/registry.d.ts +1 -1
  54. package/dist/src/tools/registry.js +60 -60
  55. package/dist/src/tools/registry.js.map +1 -1
  56. package/dist/src/tools/types.d.ts +31 -31
  57. package/dist/src/types.d.ts +33 -33
  58. package/dist/src/types.d.ts.map +1 -1
  59. package/dist/src/types.js.map +1 -1
  60. package/dist/src/utils/logger.d.ts +4 -4
  61. package/dist/src/utils/logger.d.ts.map +1 -1
  62. package/dist/src/utils/logger.js +8 -8
  63. package/dist/src/utils/logger.js.map +1 -1
  64. package/dist/src/workflow/config.d.ts +1 -1
  65. package/dist/src/workflow/config.d.ts.map +1 -1
  66. package/dist/src/workflow/config.js +18 -18
  67. package/dist/src/workflow/config.js.map +1 -1
  68. package/dist/src/workflow/steps/build.d.ts +1 -1
  69. package/dist/src/workflow/steps/build.d.ts.map +1 -1
  70. package/dist/src/workflow/steps/build.js +38 -46
  71. package/dist/src/workflow/steps/build.js.map +1 -1
  72. package/dist/src/workflow/steps/finalize.d.ts +1 -1
  73. package/dist/src/workflow/steps/finalize.d.ts.map +1 -1
  74. package/dist/src/workflow/steps/finalize.js +48 -54
  75. package/dist/src/workflow/steps/finalize.js.map +1 -1
  76. package/dist/src/workflow/steps/plan.d.ts +1 -1
  77. package/dist/src/workflow/steps/plan.d.ts.map +1 -1
  78. package/dist/src/workflow/steps/plan.js +46 -58
  79. package/dist/src/workflow/steps/plan.js.map +1 -1
  80. package/dist/src/workflow/steps/research.d.ts +1 -1
  81. package/dist/src/workflow/steps/research.d.ts.map +1 -1
  82. package/dist/src/workflow/steps/research.js +56 -68
  83. package/dist/src/workflow/steps/research.js.map +1 -1
  84. package/dist/src/workflow/types.d.ts +12 -12
  85. package/dist/src/workflow/types.d.ts.map +1 -1
  86. package/dist/src/workflow/utils.d.ts +1 -1
  87. package/dist/src/workflow/utils.d.ts.map +1 -1
  88. package/dist/src/workflow/utils.js +4 -7
  89. package/dist/src/workflow/utils.js.map +1 -1
  90. package/package.json +6 -6
  91. package/src/adapters/claude/claude-adapter.ts +168 -220
  92. package/src/adapters/claude/tool-mapper.ts +2 -2
  93. package/src/adapters/types.ts +1 -1
  94. package/src/agent.ts +444 -579
  95. package/src/agents/execution.ts +1 -1
  96. package/src/agents/planning.ts +1 -1
  97. package/src/agents/research.ts +1 -0
  98. package/src/file-manager.ts +63 -64
  99. package/src/git-manager.ts +88 -144
  100. package/src/posthog-api.ts +82 -122
  101. package/src/prompt-builder.ts +135 -180
  102. package/src/task-manager.ts +30 -38
  103. package/src/task-progress-reporter.ts +59 -70
  104. package/src/template-manager.ts +45 -98
  105. package/src/todo-manager.ts +30 -35
  106. package/src/tools/registry.ts +62 -62
  107. package/src/tools/types.ts +36 -36
  108. package/src/types.ts +71 -93
  109. package/src/utils/logger.ts +56 -62
  110. package/src/workflow/config.ts +48 -48
  111. package/src/workflow/steps/build.ts +113 -122
  112. package/src/workflow/steps/finalize.ts +182 -214
  113. package/src/workflow/steps/plan.ts +131 -151
  114. package/src/workflow/steps/research.ts +186 -205
  115. package/src/workflow/types.ts +36 -38
  116. package/src/workflow/utils.ts +34 -37
@@ -1,222 +1,203 @@
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";
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';
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", {
27
- taskId: task.id,
28
- hasQuestions: !!existingResearch.questions,
29
- answered: existingResearch.answered,
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 || {}) },
30
81
  });
31
82
 
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
- });
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
+ }
38
98
 
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
- }
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 };
53
107
  }
54
108
 
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
- }
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');
102
116
  }
103
- }
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 };
104
137
  }
105
- } catch (error) {
106
- stepLogger.error("Error during research step query", error);
107
- throw error;
108
- }
109
138
 
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");
139
+ // Add answered/answers fields to evaluation
140
+ if (evaluation.questions && evaluation.questions.length > 0) {
141
+ evaluation.answered = false;
142
+ evaluation.answers = undefined;
127
143
  }
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),
139
- });
140
- emitEvent({
141
- type: "error",
142
- ts: Date.now(),
143
- message: `Failed to parse research JSON: ${
144
- error instanceof Error ? error.message : String(error)
145
- }`,
146
- });
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,
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,
186
151
  });
187
152
 
188
153
  emitEvent({
189
- type: "artifact",
190
- ts: Date.now(),
191
- kind: "research_questions",
192
- content: evaluation.questions,
154
+ type: 'artifact',
155
+ ts: Date.now(),
156
+ kind: 'research_evaluation',
157
+ content: evaluation,
193
158
  });
194
- } else {
195
- stepLogger.info("Actionability score acceptable, proceeding to planning", {
196
- taskId: task.id,
197
- score: evaluation.actionabilityScore,
159
+
160
+ await gitManager.addAllPostHogFiles();
161
+ await finalizeStepGitActions(context, step, {
162
+ commitMessage: `Research phase for ${task.title}`,
198
163
  });
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" };
164
+
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' };
222
203
  };
@@ -1,53 +1,51 @@
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";
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';
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, unknown>;
23
- posthogAPI?: PostHogAPIClient;
24
- emitEvent: (event: unknown) => void;
25
- stepResults: Record<string, unknown>;
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>;
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 = (
50
- runtime: WorkflowStepRuntime,
51
- ) => Promise<WorkflowStepResult>;
49
+ export type WorkflowStepRunner = (runtime: WorkflowStepRuntime) => Promise<WorkflowStepResult>;
52
50
 
53
51
  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,44 +10,41 @@ 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", {
47
- stepId: step.id,
48
- branch: branchName,
49
- });
50
- }
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
+ }
51
48
 
52
- return true;
49
+ return true;
53
50
  }