@posthog/agent 1.30.0 → 2.0.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.
- package/dist/index.d.ts +51 -95
- package/dist/index.js +887 -2187
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/acp-extensions.ts +1 -51
- package/src/adapters/claude/claude.ts +508 -104
- package/src/adapters/claude/tools.ts +178 -101
- package/src/adapters/connection.ts +95 -0
- package/src/agent.ts +30 -176
- package/src/file-manager.ts +1 -34
- package/src/tools/registry.ts +5 -0
- package/src/tools/types.ts +6 -0
- package/src/types.ts +3 -23
- package/src/worktree-manager.ts +92 -46
- package/dist/templates/plan-template.md +0 -41
- package/src/agents/execution.ts +0 -37
- package/src/agents/planning.ts +0 -60
- package/src/agents/research.ts +0 -160
- package/src/prompt-builder.ts +0 -499
- package/src/template-manager.ts +0 -236
- package/src/templates/plan-template.md +0 -41
- package/src/workflow/config.ts +0 -53
- package/src/workflow/steps/build.ts +0 -135
- package/src/workflow/steps/finalize.ts +0 -241
- package/src/workflow/steps/plan.ts +0 -167
- package/src/workflow/steps/research.ts +0 -223
- package/src/workflow/types.ts +0 -62
- package/src/workflow/utils.ts +0 -53
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
-
import { POSTHOG_NOTIFICATIONS } from "../../acp-extensions.js";
|
|
3
|
-
import { PLANNING_SYSTEM_PROMPT } from "../../agents/planning.js";
|
|
4
|
-
import { TodoManager } from "../../todo-manager.js";
|
|
5
|
-
import type { WorkflowStepRunner } from "../types.js";
|
|
6
|
-
import { finalizeStepGitActions } from "../utils.js";
|
|
7
|
-
|
|
8
|
-
export const planStep: WorkflowStepRunner = async ({ step, context }) => {
|
|
9
|
-
const {
|
|
10
|
-
task,
|
|
11
|
-
cwd,
|
|
12
|
-
isCloudMode,
|
|
13
|
-
options,
|
|
14
|
-
logger,
|
|
15
|
-
fileManager,
|
|
16
|
-
gitManager,
|
|
17
|
-
promptBuilder,
|
|
18
|
-
sessionId,
|
|
19
|
-
mcpServers,
|
|
20
|
-
sendNotification,
|
|
21
|
-
} = context;
|
|
22
|
-
|
|
23
|
-
const stepLogger = logger.child("PlanStep");
|
|
24
|
-
|
|
25
|
-
const existingPlan = await fileManager.readPlan(task.id);
|
|
26
|
-
if (existingPlan) {
|
|
27
|
-
stepLogger.info("Plan already exists, skipping step", { taskId: task.id });
|
|
28
|
-
return { status: "skipped" };
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const researchData = await fileManager.readResearch(task.id);
|
|
32
|
-
if (researchData?.questions && !researchData.answered) {
|
|
33
|
-
stepLogger.info("Waiting for answered research questions", {
|
|
34
|
-
taskId: task.id,
|
|
35
|
-
});
|
|
36
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.PHASE_COMPLETE, {
|
|
37
|
-
sessionId,
|
|
38
|
-
phase: "research_questions",
|
|
39
|
-
});
|
|
40
|
-
return { status: "skipped", halt: true };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
stepLogger.info("Starting planning phase", { taskId: task.id });
|
|
44
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.PHASE_START, {
|
|
45
|
-
sessionId,
|
|
46
|
-
phase: "planning",
|
|
47
|
-
});
|
|
48
|
-
let researchContext = "";
|
|
49
|
-
if (researchData) {
|
|
50
|
-
researchContext += `## Research Context\n\n${researchData.context}\n\n`;
|
|
51
|
-
if (researchData.keyFiles.length > 0) {
|
|
52
|
-
researchContext += `**Key Files:**\n${researchData.keyFiles.map((f) => `- ${f}`).join("\n")}\n\n`;
|
|
53
|
-
}
|
|
54
|
-
if (researchData.blockers && researchData.blockers.length > 0) {
|
|
55
|
-
researchContext += `**Considerations:**\n${researchData.blockers.map((b) => `- ${b}`).join("\n")}\n\n`;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Add answered questions if they exist
|
|
59
|
-
if (
|
|
60
|
-
researchData.questions &&
|
|
61
|
-
researchData.answers &&
|
|
62
|
-
researchData.answered
|
|
63
|
-
) {
|
|
64
|
-
researchContext += `## Implementation Decisions\n\n`;
|
|
65
|
-
for (const question of researchData.questions) {
|
|
66
|
-
const answer = researchData.answers.find(
|
|
67
|
-
(a) => a.questionId === question.id,
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
researchContext += `### ${question.question}\n\n`;
|
|
71
|
-
if (answer) {
|
|
72
|
-
researchContext += `**Selected:** ${answer.selectedOption}\n`;
|
|
73
|
-
if (answer.customInput) {
|
|
74
|
-
researchContext += `**Details:** ${answer.customInput}\n`;
|
|
75
|
-
}
|
|
76
|
-
} else {
|
|
77
|
-
researchContext += `**Selected:** Not answered\n`;
|
|
78
|
-
}
|
|
79
|
-
researchContext += `\n`;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const planningPrompt = await promptBuilder.buildPlanningPrompt(task, cwd);
|
|
85
|
-
const fullPrompt = `${PLANNING_SYSTEM_PROMPT}\n\n${planningPrompt}\n\n${researchContext}`;
|
|
86
|
-
|
|
87
|
-
const baseOptions: Record<string, unknown> = {
|
|
88
|
-
model: step.model,
|
|
89
|
-
cwd,
|
|
90
|
-
permissionMode: "plan",
|
|
91
|
-
settingSources: ["local"],
|
|
92
|
-
mcpServers,
|
|
93
|
-
// Allow research tools: read-only operations, web search, MCP resources, and ExitPlanMode
|
|
94
|
-
allowedTools: [
|
|
95
|
-
"Read",
|
|
96
|
-
"Glob",
|
|
97
|
-
"Grep",
|
|
98
|
-
"WebFetch",
|
|
99
|
-
"WebSearch",
|
|
100
|
-
"ListMcpResources",
|
|
101
|
-
"ReadMcpResource",
|
|
102
|
-
"ExitPlanMode",
|
|
103
|
-
"TodoWrite",
|
|
104
|
-
"BashOutput",
|
|
105
|
-
],
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const response = query({
|
|
109
|
-
prompt: fullPrompt,
|
|
110
|
-
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
const todoManager = new TodoManager(fileManager, stepLogger);
|
|
114
|
-
|
|
115
|
-
let planContent = "";
|
|
116
|
-
try {
|
|
117
|
-
for await (const message of response) {
|
|
118
|
-
const todoList = await todoManager.checkAndPersistFromMessage(
|
|
119
|
-
message,
|
|
120
|
-
task.id,
|
|
121
|
-
);
|
|
122
|
-
if (todoList) {
|
|
123
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.ARTIFACT, {
|
|
124
|
-
sessionId,
|
|
125
|
-
kind: "todos",
|
|
126
|
-
content: todoList,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Extract text content for plan
|
|
131
|
-
if (message.type === "assistant" && message.message?.content) {
|
|
132
|
-
for (const block of message.message.content) {
|
|
133
|
-
if (block.type === "text" && block.text) {
|
|
134
|
-
planContent += `${block.text}\n`;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
} catch (error) {
|
|
140
|
-
stepLogger.error("Error during plan step query", error);
|
|
141
|
-
throw error;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (planContent.trim()) {
|
|
145
|
-
await fileManager.writePlan(task.id, planContent.trim());
|
|
146
|
-
stepLogger.info("Plan completed", { taskId: task.id });
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
await gitManager.addAllPostHogFiles();
|
|
150
|
-
await finalizeStepGitActions(context, step, {
|
|
151
|
-
commitMessage: `Planning phase for ${task.title}`,
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
if (!isCloudMode) {
|
|
155
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.PHASE_COMPLETE, {
|
|
156
|
-
sessionId,
|
|
157
|
-
phase: "planning",
|
|
158
|
-
});
|
|
159
|
-
return { status: "completed", halt: true };
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.PHASE_COMPLETE, {
|
|
163
|
-
sessionId,
|
|
164
|
-
phase: "planning",
|
|
165
|
-
});
|
|
166
|
-
return { status: "completed" };
|
|
167
|
-
};
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
-
import { POSTHOG_NOTIFICATIONS } from "../../acp-extensions.js";
|
|
3
|
-
import { RESEARCH_SYSTEM_PROMPT } from "../../agents/research.js";
|
|
4
|
-
import type { ResearchEvaluation } from "../../types.js";
|
|
5
|
-
import type { WorkflowStepRunner } from "../types.js";
|
|
6
|
-
import { finalizeStepGitActions } from "../utils.js";
|
|
7
|
-
|
|
8
|
-
export const researchStep: WorkflowStepRunner = async ({ step, context }) => {
|
|
9
|
-
const {
|
|
10
|
-
task,
|
|
11
|
-
cwd,
|
|
12
|
-
isCloudMode,
|
|
13
|
-
options,
|
|
14
|
-
logger,
|
|
15
|
-
fileManager,
|
|
16
|
-
gitManager,
|
|
17
|
-
promptBuilder,
|
|
18
|
-
sessionId,
|
|
19
|
-
mcpServers,
|
|
20
|
-
sendNotification,
|
|
21
|
-
} = context;
|
|
22
|
-
|
|
23
|
-
const stepLogger = logger.child("ResearchStep");
|
|
24
|
-
|
|
25
|
-
const existingResearch = await fileManager.readResearch(task.id);
|
|
26
|
-
if (existingResearch) {
|
|
27
|
-
stepLogger.info("Research already exists", {
|
|
28
|
-
taskId: task.id,
|
|
29
|
-
hasQuestions: !!existingResearch.questions,
|
|
30
|
-
answered: existingResearch.answered,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// If there are unanswered questions, re-emit them so UI can prompt user
|
|
34
|
-
if (existingResearch.questions && !existingResearch.answered) {
|
|
35
|
-
stepLogger.info("Re-emitting unanswered research questions", {
|
|
36
|
-
taskId: task.id,
|
|
37
|
-
questionCount: existingResearch.questions.length,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.ARTIFACT, {
|
|
41
|
-
sessionId,
|
|
42
|
-
kind: "research_questions",
|
|
43
|
-
content: existingResearch.questions,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// In local mode, halt to allow user to answer
|
|
47
|
-
if (!isCloudMode) {
|
|
48
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.PHASE_COMPLETE, {
|
|
49
|
-
sessionId,
|
|
50
|
-
phase: "research",
|
|
51
|
-
});
|
|
52
|
-
return { status: "skipped", halt: true };
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return { status: "skipped" };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
stepLogger.info("Starting research phase", { taskId: task.id });
|
|
60
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.PHASE_START, {
|
|
61
|
-
sessionId,
|
|
62
|
-
phase: "research",
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const researchPrompt = await promptBuilder.buildResearchPrompt(task, cwd);
|
|
66
|
-
const fullPrompt = `${RESEARCH_SYSTEM_PROMPT}\n\n${researchPrompt}`;
|
|
67
|
-
|
|
68
|
-
const baseOptions: Record<string, unknown> = {
|
|
69
|
-
model: step.model,
|
|
70
|
-
cwd,
|
|
71
|
-
permissionMode: "plan",
|
|
72
|
-
settingSources: ["local"],
|
|
73
|
-
mcpServers,
|
|
74
|
-
// Allow research tools: read-only operations, web search, and MCP resources
|
|
75
|
-
allowedTools: [
|
|
76
|
-
"Read",
|
|
77
|
-
"Glob",
|
|
78
|
-
"Grep",
|
|
79
|
-
"WebFetch",
|
|
80
|
-
"WebSearch",
|
|
81
|
-
"ListMcpResources",
|
|
82
|
-
"ReadMcpResource",
|
|
83
|
-
"TodoWrite",
|
|
84
|
-
"BashOutput",
|
|
85
|
-
],
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const response = query({
|
|
89
|
-
prompt: fullPrompt,
|
|
90
|
-
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
let jsonContent = "";
|
|
94
|
-
try {
|
|
95
|
-
for await (const message of response) {
|
|
96
|
-
// Extract text content from assistant messages
|
|
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
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
} catch (error) {
|
|
106
|
-
stepLogger.error("Error during research step query", error);
|
|
107
|
-
throw error;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (!jsonContent.trim()) {
|
|
111
|
-
stepLogger.error("No JSON output from research agent", { taskId: task.id });
|
|
112
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.ERROR, {
|
|
113
|
-
sessionId,
|
|
114
|
-
message: "Research agent returned no output",
|
|
115
|
-
});
|
|
116
|
-
return { status: "completed", halt: true };
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Parse JSON response
|
|
120
|
-
let evaluation: ResearchEvaluation;
|
|
121
|
-
try {
|
|
122
|
-
// Extract JSON from potential markdown code blocks or other wrapping
|
|
123
|
-
const jsonMatch = jsonContent.match(/\{[\s\S]*\}/);
|
|
124
|
-
if (!jsonMatch) {
|
|
125
|
-
throw new Error("No JSON object found in response");
|
|
126
|
-
}
|
|
127
|
-
evaluation = JSON.parse(jsonMatch[0]);
|
|
128
|
-
stepLogger.info("Parsed research evaluation", {
|
|
129
|
-
taskId: task.id,
|
|
130
|
-
score: evaluation.actionabilityScore,
|
|
131
|
-
hasQuestions: !!evaluation.questions,
|
|
132
|
-
});
|
|
133
|
-
} catch (error) {
|
|
134
|
-
stepLogger.error("Failed to parse research JSON", {
|
|
135
|
-
taskId: task.id,
|
|
136
|
-
error: error instanceof Error ? error.message : String(error),
|
|
137
|
-
content: jsonContent.substring(0, 500),
|
|
138
|
-
});
|
|
139
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.ERROR, {
|
|
140
|
-
sessionId,
|
|
141
|
-
message: `Failed to parse research JSON: ${
|
|
142
|
-
error instanceof Error ? error.message : String(error)
|
|
143
|
-
}`,
|
|
144
|
-
});
|
|
145
|
-
return { status: "completed", halt: true };
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Add answered/answers fields to evaluation
|
|
149
|
-
if (evaluation.questions && evaluation.questions.length > 0) {
|
|
150
|
-
evaluation.answered = false;
|
|
151
|
-
evaluation.answers = undefined;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Always write research.json
|
|
155
|
-
await fileManager.writeResearch(task.id, evaluation);
|
|
156
|
-
stepLogger.info("Research evaluation written", {
|
|
157
|
-
taskId: task.id,
|
|
158
|
-
score: evaluation.actionabilityScore,
|
|
159
|
-
hasQuestions: !!evaluation.questions,
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.ARTIFACT, {
|
|
163
|
-
sessionId,
|
|
164
|
-
kind: "research_evaluation",
|
|
165
|
-
content: evaluation,
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
await gitManager.addAllPostHogFiles();
|
|
169
|
-
await finalizeStepGitActions(context, step, {
|
|
170
|
-
commitMessage: `Research phase for ${task.title}`,
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// Log whether questions need answering
|
|
174
|
-
if (
|
|
175
|
-
evaluation.actionabilityScore < 0.7 &&
|
|
176
|
-
evaluation.questions &&
|
|
177
|
-
evaluation.questions.length > 0
|
|
178
|
-
) {
|
|
179
|
-
stepLogger.info("Actionability score below threshold, questions needed", {
|
|
180
|
-
taskId: task.id,
|
|
181
|
-
score: evaluation.actionabilityScore,
|
|
182
|
-
questionCount: evaluation.questions.length,
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.ARTIFACT, {
|
|
186
|
-
sessionId,
|
|
187
|
-
kind: "research_questions",
|
|
188
|
-
content: evaluation.questions,
|
|
189
|
-
});
|
|
190
|
-
} else {
|
|
191
|
-
stepLogger.info("Actionability score acceptable, proceeding to planning", {
|
|
192
|
-
taskId: task.id,
|
|
193
|
-
score: evaluation.actionabilityScore,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// In local mode, always halt after research for user review
|
|
198
|
-
if (!isCloudMode) {
|
|
199
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.PHASE_COMPLETE, {
|
|
200
|
-
sessionId,
|
|
201
|
-
phase: "research",
|
|
202
|
-
});
|
|
203
|
-
return { status: "completed", halt: true };
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// In cloud mode, check if questions need answering
|
|
207
|
-
const researchData = await fileManager.readResearch(task.id);
|
|
208
|
-
if (researchData?.questions && !researchData.answered) {
|
|
209
|
-
// Questions need answering - halt for user input in cloud mode too
|
|
210
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.PHASE_COMPLETE, {
|
|
211
|
-
sessionId,
|
|
212
|
-
phase: "research",
|
|
213
|
-
});
|
|
214
|
-
return { status: "completed", halt: true };
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// No questions or questions already answered - proceed to planning
|
|
218
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.PHASE_COMPLETE, {
|
|
219
|
-
sessionId,
|
|
220
|
-
phase: "research",
|
|
221
|
-
});
|
|
222
|
-
return { status: "completed" };
|
|
223
|
-
};
|
package/src/workflow/types.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { AgentSideConnection } from "@agentclientprotocol/sdk";
|
|
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 { PermissionMode, Task, TaskExecutionOptions } from "../types.js";
|
|
7
|
-
import type { Logger } from "../utils/logger.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Function type for sending custom PostHog notifications via ACP extNotification.
|
|
11
|
-
* Used by workflow steps to emit artifacts, phase updates, etc.
|
|
12
|
-
*/
|
|
13
|
-
export type SendNotification = (
|
|
14
|
-
method: string,
|
|
15
|
-
params: Record<string, unknown>,
|
|
16
|
-
) => Promise<void>;
|
|
17
|
-
|
|
18
|
-
export interface WorkflowRuntime {
|
|
19
|
-
task: Task;
|
|
20
|
-
taskSlug: string;
|
|
21
|
-
runId: string;
|
|
22
|
-
cwd: string;
|
|
23
|
-
isCloudMode: boolean;
|
|
24
|
-
options: TaskExecutionOptions;
|
|
25
|
-
logger: Logger;
|
|
26
|
-
fileManager: PostHogFileManager;
|
|
27
|
-
gitManager: GitManager;
|
|
28
|
-
promptBuilder: PromptBuilder;
|
|
29
|
-
connection: AgentSideConnection;
|
|
30
|
-
sessionId: string;
|
|
31
|
-
mcpServers?: Record<string, unknown>;
|
|
32
|
-
posthogAPI?: PostHogAPIClient;
|
|
33
|
-
sendNotification: SendNotification;
|
|
34
|
-
stepResults: Record<string, unknown>;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface WorkflowStepDefinition {
|
|
38
|
-
id: string;
|
|
39
|
-
name: string;
|
|
40
|
-
agent: string;
|
|
41
|
-
model: string;
|
|
42
|
-
permissionMode?: PermissionMode | string;
|
|
43
|
-
commit?: boolean;
|
|
44
|
-
push?: boolean;
|
|
45
|
-
run: WorkflowStepRunner;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface WorkflowStepRuntime {
|
|
49
|
-
step: WorkflowStepDefinition;
|
|
50
|
-
context: WorkflowRuntime;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface WorkflowStepResult {
|
|
54
|
-
status: "completed" | "skipped";
|
|
55
|
-
halt?: boolean;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export type WorkflowStepRunner = (
|
|
59
|
-
runtime: WorkflowStepRuntime,
|
|
60
|
-
) => Promise<WorkflowStepResult>;
|
|
61
|
-
|
|
62
|
-
export type WorkflowDefinition = WorkflowStepDefinition[];
|
package/src/workflow/utils.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import type { WorkflowRuntime, WorkflowStepDefinition } from "./types.js";
|
|
2
|
-
|
|
3
|
-
interface FinalizeGitOptions {
|
|
4
|
-
commitMessage: string;
|
|
5
|
-
allowEmptyCommit?: boolean;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Commits (and optionally pushes) any staged changes according to the step configuration.
|
|
10
|
-
* Returns true if a commit was created.
|
|
11
|
-
*/
|
|
12
|
-
export async function finalizeStepGitActions(
|
|
13
|
-
context: WorkflowRuntime,
|
|
14
|
-
step: WorkflowStepDefinition,
|
|
15
|
-
options: FinalizeGitOptions,
|
|
16
|
-
): Promise<boolean> {
|
|
17
|
-
if (!step.commit) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const { gitManager, logger } = context;
|
|
22
|
-
const hasStagedChanges = await gitManager.hasStagedChanges();
|
|
23
|
-
|
|
24
|
-
if (!hasStagedChanges && !options.allowEmptyCommit) {
|
|
25
|
-
logger.debug("No staged changes to commit for step", { stepId: step.id });
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
51
|
-
|
|
52
|
-
return true;
|
|
53
|
-
}
|