agentic-forge 0.0.0 → 0.7.1

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 (212) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +64 -24
  3. package/{src/claude → dist/authoring}/.claude/skills/workflow-builder/SKILL.md +2 -2
  4. package/{src/claude → dist/authoring}/.claude/skills/workflow-builder/references/REFERENCE.md +9 -3
  5. package/{src/claude → dist/authoring}/.claude/skills/workflow-builder/references/workflow-example.yaml +15 -8
  6. package/dist/checkpoints/manager.d.ts +5 -0
  7. package/dist/checkpoints/manager.js +87 -0
  8. package/dist/checkpoints/manager.js.map +1 -0
  9. package/{src → dist}/claude/.claude/skills/analyze/SKILL.md +1 -1
  10. package/{src → dist}/claude/.claude/skills/create-checkpoint/SKILL.md +1 -1
  11. package/{src → dist}/claude/.claude/skills/create-log/SKILL.md +1 -1
  12. package/{src → dist}/claude/.claude/skills/fix-analyze/SKILL.md +1 -1
  13. package/{src → dist}/claude/.claude/skills/git-branch/SKILL.md +1 -1
  14. package/{src → dist}/claude/.claude/skills/git-commit/SKILL.md +1 -1
  15. package/{src → dist}/claude/.claude/skills/git-pr/SKILL.md +1 -1
  16. package/{src → dist}/claude/.claude/skills/sdlc-plan/SKILL.md +1 -1
  17. package/{src → dist}/claude/.claude/skills/sdlc-review/SKILL.md +1 -1
  18. package/dist/cli.d.ts +3 -0
  19. package/dist/cli.js +173 -0
  20. package/dist/cli.js.map +1 -0
  21. package/dist/commands/authoring-dir.d.ts +2 -0
  22. package/dist/commands/authoring-dir.js +9 -0
  23. package/dist/commands/authoring-dir.js.map +1 -0
  24. package/dist/commands/config-cmd.d.ts +2 -0
  25. package/dist/commands/config-cmd.js +30 -0
  26. package/dist/commands/config-cmd.js.map +1 -0
  27. package/{src/commands/index.ts → dist/commands/index.d.ts} +2 -10
  28. package/dist/commands/index.js +14 -0
  29. package/dist/commands/index.js.map +1 -0
  30. package/dist/commands/init.d.ts +6 -0
  31. package/dist/commands/init.js +83 -0
  32. package/dist/commands/init.js.map +1 -0
  33. package/dist/commands/release-notes.d.ts +5 -0
  34. package/dist/commands/release-notes.js +68 -0
  35. package/dist/commands/release-notes.js.map +1 -0
  36. package/dist/commands/resume.d.ts +5 -0
  37. package/dist/commands/resume.js +79 -0
  38. package/dist/commands/resume.js.map +1 -0
  39. package/dist/commands/run.d.ts +27 -0
  40. package/dist/commands/run.js +243 -0
  41. package/dist/commands/run.js.map +1 -0
  42. package/dist/commands/shortcuts.d.ts +2 -0
  43. package/dist/commands/shortcuts.js +11 -0
  44. package/dist/commands/shortcuts.js.map +1 -0
  45. package/dist/commands/skills-dir.d.ts +2 -0
  46. package/dist/commands/skills-dir.js +9 -0
  47. package/dist/commands/skills-dir.js.map +1 -0
  48. package/dist/commands/status.d.ts +4 -0
  49. package/dist/commands/status.js +99 -0
  50. package/dist/commands/status.js.map +1 -0
  51. package/dist/commands/update.d.ts +4 -0
  52. package/dist/commands/update.js +65 -0
  53. package/dist/commands/update.js.map +1 -0
  54. package/dist/commands/version.d.ts +3 -0
  55. package/dist/commands/version.js +26 -0
  56. package/dist/commands/version.js.map +1 -0
  57. package/dist/commands/workflows.d.ts +4 -0
  58. package/dist/commands/workflows.js +111 -0
  59. package/dist/commands/workflows.js.map +1 -0
  60. package/dist/config.d.ts +8 -0
  61. package/dist/config.js +110 -0
  62. package/dist/config.js.map +1 -0
  63. package/dist/console.d.ts +103 -0
  64. package/dist/console.js +670 -0
  65. package/dist/console.js.map +1 -0
  66. package/dist/executor.d.ts +27 -0
  67. package/dist/executor.js +236 -0
  68. package/dist/executor.js.map +1 -0
  69. package/dist/git/worktree.d.ts +23 -0
  70. package/dist/git/worktree.js +170 -0
  71. package/dist/git/worktree.js.map +1 -0
  72. package/dist/logging/logger.d.ts +27 -0
  73. package/dist/logging/logger.js +69 -0
  74. package/dist/logging/logger.js.map +1 -0
  75. package/dist/orchestrator.d.ts +44 -0
  76. package/dist/orchestrator.js +587 -0
  77. package/dist/orchestrator.js.map +1 -0
  78. package/dist/parser.d.ts +17 -0
  79. package/dist/parser.js +184 -0
  80. package/dist/parser.js.map +1 -0
  81. package/dist/progress.d.ts +29 -0
  82. package/dist/progress.js +275 -0
  83. package/dist/progress.js.map +1 -0
  84. package/dist/ralph-loop.d.ts +26 -0
  85. package/dist/ralph-loop.js +194 -0
  86. package/dist/ralph-loop.js.map +1 -0
  87. package/dist/renderer.d.ts +15 -0
  88. package/dist/renderer.js +123 -0
  89. package/dist/renderer.js.map +1 -0
  90. package/dist/runner.d.ts +84 -0
  91. package/dist/runner.js +529 -0
  92. package/dist/runner.js.map +1 -0
  93. package/dist/signal-manager.d.ts +16 -0
  94. package/dist/signal-manager.js +50 -0
  95. package/dist/signal-manager.js.map +1 -0
  96. package/dist/steps/base.d.ts +28 -0
  97. package/dist/steps/base.js +23 -0
  98. package/dist/steps/base.js.map +1 -0
  99. package/dist/steps/conditional-step.d.ts +12 -0
  100. package/dist/steps/conditional-step.js +106 -0
  101. package/dist/steps/conditional-step.js.map +1 -0
  102. package/{src/steps/index.ts → dist/steps/index.d.ts} +1 -9
  103. package/dist/steps/index.js +8 -0
  104. package/dist/steps/index.js.map +1 -0
  105. package/dist/steps/parallel-step.d.ts +11 -0
  106. package/dist/steps/parallel-step.js +166 -0
  107. package/dist/steps/parallel-step.js.map +1 -0
  108. package/dist/steps/prompt-step.d.ts +8 -0
  109. package/dist/steps/prompt-step.js +94 -0
  110. package/dist/steps/prompt-step.js.map +1 -0
  111. package/dist/steps/ralph-loop-step.d.ts +8 -0
  112. package/dist/steps/ralph-loop-step.js +132 -0
  113. package/dist/steps/ralph-loop-step.js.map +1 -0
  114. package/dist/steps/serial-step.d.ts +10 -0
  115. package/dist/steps/serial-step.js +57 -0
  116. package/dist/steps/serial-step.js.map +1 -0
  117. package/dist/types.d.ts +118 -0
  118. package/dist/types.js +10 -0
  119. package/dist/types.js.map +1 -0
  120. package/package.json +59 -2
  121. package/.gitattributes +0 -24
  122. package/.github/workflows/ci.yml +0 -70
  123. package/.markdownlint-cli2.jsonc +0 -16
  124. package/.prettierignore +0 -3
  125. package/.prettierrc +0 -6
  126. package/.vscode/agentic-forge.code-workspace +0 -26
  127. package/CHANGELOG.md +0 -100
  128. package/CLAUDE.md +0 -158
  129. package/CONTRIBUTING.md +0 -152
  130. package/biome.json +0 -21
  131. package/scripts/copy-assets.js +0 -21
  132. package/src/checkpoints/manager.ts +0 -119
  133. package/src/cli.ts +0 -182
  134. package/src/commands/config-cmd.ts +0 -28
  135. package/src/commands/init.ts +0 -96
  136. package/src/commands/release-notes.ts +0 -85
  137. package/src/commands/resume.ts +0 -103
  138. package/src/commands/run.ts +0 -234
  139. package/src/commands/shortcuts.ts +0 -11
  140. package/src/commands/skills-dir.ts +0 -11
  141. package/src/commands/status.ts +0 -112
  142. package/src/commands/update.ts +0 -64
  143. package/src/commands/version.ts +0 -27
  144. package/src/commands/workflows.ts +0 -129
  145. package/src/config.ts +0 -129
  146. package/src/console.ts +0 -790
  147. package/src/executor.ts +0 -354
  148. package/src/git/worktree.ts +0 -236
  149. package/src/logging/logger.ts +0 -95
  150. package/src/orchestrator.ts +0 -815
  151. package/src/parser.ts +0 -225
  152. package/src/progress.ts +0 -306
  153. package/src/ralph-loop.ts +0 -260
  154. package/src/renderer.ts +0 -164
  155. package/src/runner.ts +0 -634
  156. package/src/signal-manager.ts +0 -55
  157. package/src/steps/base.ts +0 -71
  158. package/src/steps/conditional-step.ts +0 -144
  159. package/src/steps/parallel-step.ts +0 -213
  160. package/src/steps/prompt-step.ts +0 -121
  161. package/src/steps/ralph-loop-step.ts +0 -186
  162. package/src/steps/serial-step.ts +0 -84
  163. package/src/types.ts +0 -141
  164. package/tests/config.test.ts +0 -219
  165. package/tests/console.test.ts +0 -506
  166. package/tests/executor.test.ts +0 -339
  167. package/tests/init.test.ts +0 -86
  168. package/tests/logger.test.ts +0 -110
  169. package/tests/parser.test.ts +0 -290
  170. package/tests/progress.test.ts +0 -345
  171. package/tests/ralph-loop.test.ts +0 -418
  172. package/tests/renderer.test.ts +0 -350
  173. package/tests/runner.test.ts +0 -497
  174. package/tests/setup.test.ts +0 -7
  175. package/tests/signal-manager.test.ts +0 -26
  176. package/tests/steps.test.ts +0 -412
  177. package/tests/worktree.test.ts +0 -411
  178. package/tsconfig.json +0 -18
  179. package/vitest.config.ts +0 -8
  180. /package/{src → dist}/agents/explorer.md +0 -0
  181. /package/{src → dist}/agents/reviewer.md +0 -0
  182. /package/{src → dist}/claude/.claude/skills/analyze/references/bug.md +0 -0
  183. /package/{src → dist}/claude/.claude/skills/analyze/references/debt.md +0 -0
  184. /package/{src → dist}/claude/.claude/skills/analyze/references/doc.md +0 -0
  185. /package/{src → dist}/claude/.claude/skills/analyze/references/security.md +0 -0
  186. /package/{src → dist}/claude/.claude/skills/analyze/references/style.md +0 -0
  187. /package/{src → dist}/claude/.claude/skills/orchestrate/SKILL.md +0 -0
  188. /package/{src → dist}/claude/.claude/skills/sdlc-plan/references/bug.md +0 -0
  189. /package/{src → dist}/claude/.claude/skills/sdlc-plan/references/chore.md +0 -0
  190. /package/{src → dist}/claude/.claude/skills/sdlc-plan/references/feature.md +0 -0
  191. /package/{src → dist}/prompts/agentic-system.md +0 -0
  192. /package/{src → dist}/templates/analysis/bug.md.j2 +0 -0
  193. /package/{src → dist}/templates/analysis/debt.md.j2 +0 -0
  194. /package/{src → dist}/templates/analysis/doc.md.j2 +0 -0
  195. /package/{src → dist}/templates/analysis/security.md.j2 +0 -0
  196. /package/{src → dist}/templates/analysis/style.md.j2 +0 -0
  197. /package/{src → dist}/templates/analysis-summary.md.j2 +0 -0
  198. /package/{src → dist}/templates/checkpoint.md.j2 +0 -0
  199. /package/{src → dist}/templates/implementation-report.md.j2 +0 -0
  200. /package/{src → dist}/templates/memory.md.j2 +0 -0
  201. /package/{src → dist}/templates/plan-bug.md.j2 +0 -0
  202. /package/{src → dist}/templates/plan-chore.md.j2 +0 -0
  203. /package/{src → dist}/templates/plan-feature.md.j2 +0 -0
  204. /package/{src → dist}/templates/progress.json.j2 +0 -0
  205. /package/{src → dist}/templates/ralph-report.md.j2 +0 -0
  206. /package/{src → dist}/workflows/analyze-codebase-merge.yaml +0 -0
  207. /package/{src → dist}/workflows/analyze-codebase.yaml +0 -0
  208. /package/{src → dist}/workflows/analyze-single.yaml +0 -0
  209. /package/{src → dist}/workflows/demo.yaml +0 -0
  210. /package/{src → dist}/workflows/one-shot.yaml +0 -0
  211. /package/{src → dist}/workflows/plan-build-review.yaml +0 -0
  212. /package/{src → dist}/workflows/ralph-loop.yaml +0 -0
package/src/parser.ts DELETED
@@ -1,225 +0,0 @@
1
- /** YAML workflow parser. */
2
-
3
- import { existsSync, readFileSync } from "node:fs";
4
- import path from "node:path";
5
- import yaml from "js-yaml";
6
- import type {
7
- GitSettings,
8
- OutputDefinition,
9
- StepDefinition,
10
- StepGitSettings,
11
- StepType,
12
- Variable,
13
- WorkflowDefinition,
14
- WorkflowSettings,
15
- } from "./types.js";
16
- import { VALID_STEP_TYPES } from "./types.js";
17
-
18
- export class WorkflowParseError extends Error {
19
- constructor(message: string) {
20
- super(message);
21
- this.name = "WorkflowParseError";
22
- }
23
- }
24
-
25
- export class WorkflowParser {
26
- basePath: string;
27
-
28
- constructor(basePath?: string) {
29
- this.basePath = basePath ?? process.cwd();
30
- }
31
-
32
- parseFile(filePath: string): WorkflowDefinition {
33
- if (!existsSync(filePath)) {
34
- throw new WorkflowParseError(`Workflow file not found: ${filePath}`);
35
- }
36
-
37
- let data: unknown;
38
- try {
39
- const content = readFileSync(filePath, "utf-8");
40
- data = yaml.load(content);
41
- } catch (e) {
42
- if (e instanceof WorkflowParseError) throw e;
43
- throw new WorkflowParseError(`Invalid YAML: ${e}`);
44
- }
45
-
46
- this.basePath = path.dirname(filePath);
47
- return this.parseDict(data);
48
- }
49
-
50
- parseString(content: string): WorkflowDefinition {
51
- let data: unknown;
52
- try {
53
- data = yaml.load(content);
54
- } catch (e) {
55
- throw new WorkflowParseError(`Invalid YAML: ${e}`);
56
- }
57
- return this.parseDict(data);
58
- }
59
-
60
- parseDict(data: unknown): WorkflowDefinition {
61
- if (!data || typeof data !== "object" || Array.isArray(data)) {
62
- throw new WorkflowParseError("Workflow must be a dictionary");
63
- }
64
-
65
- const dict = data as Record<string, unknown>;
66
- const name = this.required(dict, "name") as string;
67
- const version = (dict.version as string) ?? "1.0";
68
- const description = (dict.description as string) ?? "";
69
-
70
- const settings = this.parseSettings((dict.settings as Record<string, unknown>) ?? {});
71
- const variables = ((dict.variables as unknown[]) ?? []).map((v) =>
72
- this.parseVariable(v as Record<string, unknown>),
73
- );
74
- const steps = ((dict.steps as unknown[]) ?? []).map((s) =>
75
- this.parseStep(s as Record<string, unknown>),
76
- );
77
- const outputs = ((dict.outputs as unknown[]) ?? []).map((o) =>
78
- this.parseOutput(o as Record<string, unknown>),
79
- );
80
-
81
- return { name, version, description, settings, variables, steps, outputs };
82
- }
83
-
84
- private required(data: Record<string, unknown>, key: string): unknown {
85
- if (!(key in data)) {
86
- throw new WorkflowParseError(`Missing required field: ${key}`);
87
- }
88
- return data[key];
89
- }
90
-
91
- private parseSettings(data: Record<string, unknown>): WorkflowSettings {
92
- const gitData = (data.git as Record<string, unknown>) ?? {};
93
- const git: GitSettings = {
94
- enabled: (gitData.enabled as boolean) ?? false,
95
- worktree: (gitData.worktree as boolean) ?? false,
96
- autoCommit: (gitData["auto-commit"] as boolean) ?? true,
97
- autoPr: (gitData["auto-pr"] as boolean) ?? true,
98
- branchPrefix: (gitData["branch-prefix"] as string) ?? "agentic",
99
- };
100
- return {
101
- maxRetry: (data["max-retry"] as number) ?? 3,
102
- timeoutMinutes: (data["timeout-minutes"] as number) ?? 60,
103
- trackProgress: (data["track-progress"] as boolean) ?? true,
104
- autofix: (data.autofix as string) ?? "none",
105
- terminalOutput: (data["terminal-output"] as string) ?? "base",
106
- bypassPermissions: (data["bypass-permissions"] as boolean) ?? false,
107
- strictMode: (data["strict-mode"] as boolean) ?? false,
108
- model: (data.model as string) ?? null,
109
- requiredTools: (data["required-tools"] as string[]) ?? [],
110
- git,
111
- };
112
- }
113
-
114
- private parseVariable(data: Record<string, unknown>): Variable {
115
- return {
116
- name: this.required(data, "name") as string,
117
- type: (data.type as string) ?? "string",
118
- required: (data.required as boolean) ?? true,
119
- default: data.default,
120
- description: (data.description as string) ?? "",
121
- };
122
- }
123
-
124
- private parseStep(data: Record<string, unknown>, parentIsParallel = false): StepDefinition {
125
- const name = this.required(data, "name") as string;
126
- const typeStr = this.required(data, "type") as string;
127
-
128
- if (!VALID_STEP_TYPES.includes(typeStr as StepType)) {
129
- throw new WorkflowParseError(
130
- `Invalid step type: ${typeStr}. Valid types: ${JSON.stringify(VALID_STEP_TYPES)}`,
131
- );
132
- }
133
-
134
- const stepType = typeStr as StepType;
135
-
136
- if (parentIsParallel && stepType === "parallel") {
137
- throw new WorkflowParseError(
138
- `Nested parallel steps are not allowed: '${name}' is a parallel step inside another parallel step`,
139
- );
140
- }
141
-
142
- const step: StepDefinition = {
143
- name,
144
- type: stepType,
145
- prompt: null,
146
- agent: null,
147
- steps: [],
148
- mergeStrategy: "wait-all",
149
- mergeMode: "independent",
150
- condition: null,
151
- thenSteps: [],
152
- elseSteps: [],
153
- maxIterations: 5,
154
- completionPromise: null,
155
- message: null,
156
- pollingInterval: 15,
157
- onTimeout: "abort",
158
- model: null,
159
- stepTimeoutMinutes: null,
160
- stepMaxRetry: null,
161
- onError: "retry",
162
- checkpoint: false,
163
- dependsOn: null,
164
- git: null,
165
- };
166
-
167
- if (stepType === "prompt") {
168
- step.prompt = (data.prompt as string) ?? null;
169
- step.agent = (data.agent as string) ?? null;
170
- } else if (stepType === "parallel") {
171
- step.steps = ((data.steps as unknown[]) ?? []).map((s) =>
172
- this.parseStep(s as Record<string, unknown>, true),
173
- );
174
- step.mergeStrategy = (data["merge-strategy"] as string) ?? "wait-all";
175
- step.mergeMode = (data["merge-mode"] as string) ?? "independent";
176
- const gitData = data.git as Record<string, unknown> | undefined;
177
- if (gitData) {
178
- step.git = {
179
- worktree: (gitData.worktree as boolean) ?? false,
180
- autoPr: (gitData["auto-pr"] as boolean) ?? false,
181
- branchPrefix: (gitData["branch-prefix"] as string) ?? "agentic",
182
- } satisfies StepGitSettings;
183
- }
184
- } else if (stepType === "serial") {
185
- step.steps = ((data.steps as unknown[]) ?? []).map((s) =>
186
- this.parseStep(s as Record<string, unknown>),
187
- );
188
- } else if (stepType === "conditional") {
189
- step.condition = (data.condition as string) ?? null;
190
- step.thenSteps = ((data.then as unknown[]) ?? []).map((s) =>
191
- this.parseStep(s as Record<string, unknown>),
192
- );
193
- step.elseSteps = ((data.else as unknown[]) ?? []).map((s) =>
194
- this.parseStep(s as Record<string, unknown>),
195
- );
196
- } else if (stepType === "ralph-loop") {
197
- step.prompt = (data.prompt as string) ?? null;
198
- step.maxIterations = (data["max-iterations"] as number) ?? 5;
199
- step.completionPromise = (data["completion-promise"] as string) ?? null;
200
- } else if (stepType === "wait-for-human") {
201
- step.message = (data.message as string) ?? null;
202
- step.pollingInterval = (data["polling-interval"] as number) ?? 15;
203
- step.onTimeout = (data["on-timeout"] as string) ?? "abort";
204
- step.stepTimeoutMinutes = (data["timeout-minutes"] as number) ?? 5;
205
- }
206
-
207
- step.model = (data.model as string) ?? null;
208
- step.stepTimeoutMinutes = (data["timeout-minutes"] as number) ?? step.stepTimeoutMinutes;
209
- step.stepMaxRetry = (data["max-retry"] as number) ?? null;
210
- step.onError = (data["on-error"] as string) ?? "retry";
211
- step.checkpoint = (data.checkpoint as boolean) ?? false;
212
- step.dependsOn = (data["depends-on"] as string) ?? null;
213
-
214
- return step;
215
- }
216
-
217
- private parseOutput(data: Record<string, unknown>): OutputDefinition {
218
- return {
219
- name: this.required(data, "name") as string,
220
- template: this.required(data, "template") as string,
221
- path: this.required(data, "path") as string,
222
- when: (data.when as string) ?? "completed",
223
- };
224
- }
225
- }
package/src/progress.ts DELETED
@@ -1,306 +0,0 @@
1
- /** Workflow progress tracking. */
2
-
3
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
- import path from "node:path";
5
- import { lockSync } from "proper-lockfile";
6
- import type { ParallelBranch, StepProgress, WorkflowProgress } from "./types.js";
7
-
8
- // --- Constants ---
9
-
10
- export const WORKFLOW_STATUS = {
11
- PENDING: "pending",
12
- RUNNING: "running",
13
- COMPLETED: "completed",
14
- FAILED: "failed",
15
- PAUSED: "paused",
16
- CANCELED: "canceled",
17
- } as const;
18
-
19
- export const STEP_STATUS = {
20
- PENDING: "pending",
21
- RUNNING: "running",
22
- COMPLETED: "completed",
23
- FAILED: "failed",
24
- SKIPPED: "skipped",
25
- } as const;
26
-
27
- // --- ID and path helpers ---
28
-
29
- export function generateWorkflowId(workflowName: string): string {
30
- const now = new Date();
31
- const pad = (n: number, len = 2) => String(n).padStart(len, "0");
32
- const timestamp = `${now.getUTCFullYear()}${pad(now.getUTCMonth() + 1)}${pad(now.getUTCDate())}-${pad(now.getUTCHours())}${pad(now.getUTCMinutes())}${pad(now.getUTCSeconds())}`;
33
-
34
- let safeName = workflowName.toLowerCase().replace(/ /g, "-").replace(/_/g, "-");
35
- safeName = safeName.replace(/[^a-z0-9-]/g, "");
36
- return `${timestamp}-${safeName}`;
37
- }
38
-
39
- export function getProgressPath(workflowId: string, repoRoot?: string): string {
40
- const root = repoRoot ?? process.cwd();
41
- return path.join(root, "agentic", "outputs", workflowId, "progress.json");
42
- }
43
-
44
- // --- CRUD operations ---
45
-
46
- export function loadProgress(workflowId: string, repoRoot?: string): WorkflowProgress | null {
47
- const progressPath = getProgressPath(workflowId, repoRoot);
48
- if (!existsSync(progressPath)) {
49
- return null;
50
- }
51
- const data = JSON.parse(readFileSync(progressPath, "utf-8"));
52
- return dictToProgress(data);
53
- }
54
-
55
- export function saveProgress(progress: WorkflowProgress, repoRoot?: string): void {
56
- const progressPath = getProgressPath(progress.workflowId, repoRoot);
57
- const dir = path.dirname(progressPath);
58
- mkdirSync(dir, { recursive: true });
59
-
60
- // Ensure the file exists so proper-lockfile can resolve its path
61
- if (!existsSync(progressPath)) {
62
- writeFileSync(progressPath, "{}", "utf-8");
63
- }
64
-
65
- let release: (() => void) | undefined;
66
- try {
67
- release = lockSync(progressPath);
68
- writeFileSync(progressPath, JSON.stringify(progressToDict(progress), null, 2), "utf-8");
69
- } finally {
70
- if (release) {
71
- release();
72
- }
73
- }
74
- }
75
-
76
- export function createProgress(
77
- workflowId: string,
78
- workflowName: string,
79
- stepNames: string[],
80
- variables: Record<string, unknown>,
81
- workflowFile = "",
82
- ): WorkflowProgress {
83
- return {
84
- schemaVersion: "1.0",
85
- workflowId,
86
- workflowName,
87
- status: WORKFLOW_STATUS.RUNNING,
88
- startedAt: new Date().toISOString(),
89
- completedAt: null,
90
- currentStep: null,
91
- completedSteps: [],
92
- pendingSteps: [...stepNames],
93
- runningSteps: [],
94
- parallelBranches: [],
95
- errors: [],
96
- variables: { ...variables },
97
- stepOutputs: {},
98
- workflowFile,
99
- };
100
- }
101
-
102
- // --- Step update functions ---
103
-
104
- export function updateStepStarted(progress: WorkflowProgress, stepName: string): void {
105
- const pendingIdx = progress.pendingSteps.indexOf(stepName);
106
- if (pendingIdx !== -1) {
107
- progress.pendingSteps.splice(pendingIdx, 1);
108
- }
109
- if (!progress.runningSteps.includes(stepName)) {
110
- progress.runningSteps.push(stepName);
111
- }
112
- progress.currentStep = {
113
- name: stepName,
114
- retry_count: 0,
115
- started_at: new Date().toISOString(),
116
- };
117
- }
118
-
119
- export function updateStepCompleted(
120
- progress: WorkflowProgress,
121
- stepName: string,
122
- outputSummary = "",
123
- output?: unknown,
124
- ): void {
125
- const runIdx = progress.runningSteps.indexOf(stepName);
126
- if (runIdx !== -1) {
127
- progress.runningSteps.splice(runIdx, 1);
128
- }
129
-
130
- let startedAt: string | null = null;
131
- let retryCount = 0;
132
- if (progress.currentStep) {
133
- startedAt = (progress.currentStep.started_at as string) ?? null;
134
- retryCount = (progress.currentStep.retry_count as number) ?? 0;
135
- }
136
-
137
- const step: StepProgress = {
138
- name: stepName,
139
- status: STEP_STATUS.COMPLETED,
140
- startedAt,
141
- completedAt: new Date().toISOString(),
142
- retryCount,
143
- outputSummary,
144
- error: null,
145
- humanInput: null,
146
- };
147
- progress.completedSteps.push(step);
148
-
149
- if (output !== undefined) {
150
- progress.stepOutputs[stepName] = output;
151
- }
152
-
153
- progress.currentStep = null;
154
- }
155
-
156
- export function updateStepFailed(
157
- progress: WorkflowProgress,
158
- stepName: string,
159
- error: string,
160
- ): void {
161
- const runIdx = progress.runningSteps.indexOf(stepName);
162
- if (runIdx !== -1) {
163
- progress.runningSteps.splice(runIdx, 1);
164
- }
165
-
166
- let startedAt: string | null = null;
167
- let retryCount = 0;
168
- if (progress.currentStep) {
169
- startedAt = (progress.currentStep.started_at as string) ?? null;
170
- retryCount = (progress.currentStep.retry_count as number) ?? 0;
171
- }
172
-
173
- const step: StepProgress = {
174
- name: stepName,
175
- status: STEP_STATUS.FAILED,
176
- startedAt,
177
- completedAt: new Date().toISOString(),
178
- retryCount,
179
- error,
180
- outputSummary: "",
181
- humanInput: null,
182
- };
183
- progress.completedSteps.push(step);
184
- progress.errors.push({ step: stepName, error });
185
- progress.currentStep = null;
186
- }
187
-
188
- export function updateStepSkipped(progress: WorkflowProgress, stepName: string): void {
189
- const pendingIdx = progress.pendingSteps.indexOf(stepName);
190
- if (pendingIdx !== -1) {
191
- progress.pendingSteps.splice(pendingIdx, 1);
192
- }
193
- const runIdx = progress.runningSteps.indexOf(stepName);
194
- if (runIdx !== -1) {
195
- progress.runningSteps.splice(runIdx, 1);
196
- }
197
-
198
- const step: StepProgress = {
199
- name: stepName,
200
- status: STEP_STATUS.SKIPPED,
201
- startedAt: null,
202
- completedAt: new Date().toISOString(),
203
- retryCount: 0,
204
- outputSummary: "",
205
- error: null,
206
- humanInput: null,
207
- };
208
- progress.completedSteps.push(step);
209
- progress.currentStep = null;
210
- }
211
-
212
- export function prepareForResume(progress: WorkflowProgress): void {
213
- if (progress.runningSteps.length > 0) {
214
- progress.pendingSteps = [...progress.runningSteps, ...progress.pendingSteps];
215
- progress.runningSteps = [];
216
- }
217
-
218
- if (progress.currentStep) {
219
- const stepName = progress.currentStep.name as string | undefined;
220
- if (stepName && !progress.pendingSteps.includes(stepName)) {
221
- progress.pendingSteps.unshift(stepName);
222
- }
223
- progress.currentStep = null;
224
- }
225
-
226
- progress.status = WORKFLOW_STATUS.RUNNING;
227
- progress.completedAt = null;
228
- }
229
-
230
- // --- Serialization helpers ---
231
-
232
- export function progressToDict(progress: WorkflowProgress): Record<string, unknown> {
233
- return {
234
- schema_version: progress.schemaVersion,
235
- workflow_id: progress.workflowId,
236
- workflow_name: progress.workflowName,
237
- status: progress.status,
238
- started_at: progress.startedAt,
239
- completed_at: progress.completedAt,
240
- current_step: progress.currentStep,
241
- completed_steps: progress.completedSteps.map((s) => ({
242
- name: s.name,
243
- status: s.status,
244
- started_at: s.startedAt,
245
- completed_at: s.completedAt,
246
- retry_count: s.retryCount,
247
- output_summary: s.outputSummary,
248
- error: s.error,
249
- human_input: s.humanInput,
250
- })),
251
- pending_steps: progress.pendingSteps,
252
- running_steps: progress.runningSteps,
253
- parallel_branches: progress.parallelBranches.map((b) => ({
254
- branch_id: b.branchId,
255
- status: b.status,
256
- worktree_path: b.worktreePath,
257
- progress_file: b.progressFile,
258
- })),
259
- errors: progress.errors,
260
- variables: progress.variables,
261
- step_outputs: progress.stepOutputs,
262
- workflow_file: progress.workflowFile,
263
- };
264
- }
265
-
266
- export function dictToProgress(data: Record<string, unknown>): WorkflowProgress {
267
- const completedSteps = ((data.completed_steps as Record<string, unknown>[]) ?? []).map(
268
- (s): StepProgress => ({
269
- name: (s.name as string) ?? "",
270
- status: (s.status as string) ?? "pending",
271
- startedAt: (s.started_at as string) ?? null,
272
- completedAt: (s.completed_at as string) ?? null,
273
- retryCount: (s.retry_count as number) ?? 0,
274
- outputSummary: (s.output_summary as string) ?? "",
275
- error: (s.error as string) ?? null,
276
- humanInput: (s.human_input as string) ?? null,
277
- }),
278
- );
279
-
280
- const parallelBranches = ((data.parallel_branches as Record<string, unknown>[]) ?? []).map(
281
- (b): ParallelBranch => ({
282
- branchId: (b.branch_id as string) ?? "",
283
- status: (b.status as string) ?? "",
284
- worktreePath: (b.worktree_path as string) ?? "",
285
- progressFile: (b.progress_file as string) ?? "",
286
- }),
287
- );
288
-
289
- return {
290
- schemaVersion: (data.schema_version as string) ?? "1.0",
291
- workflowId: (data.workflow_id as string) ?? "",
292
- workflowName: (data.workflow_name as string) ?? "",
293
- status: (data.status as string) ?? "pending",
294
- startedAt: (data.started_at as string) ?? null,
295
- completedAt: (data.completed_at as string) ?? null,
296
- currentStep: (data.current_step as Record<string, unknown>) ?? null,
297
- completedSteps,
298
- pendingSteps: (data.pending_steps as string[]) ?? [],
299
- runningSteps: (data.running_steps as string[]) ?? [],
300
- parallelBranches,
301
- errors: (data.errors as Record<string, unknown>[]) ?? [],
302
- variables: (data.variables as Record<string, unknown>) ?? {},
303
- stepOutputs: (data.step_outputs as Record<string, unknown>) ?? {},
304
- workflowFile: (data.workflow_file as string) ?? "",
305
- };
306
- }