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
@@ -1,418 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import path from "node:path";
4
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
- import {
6
- type CompletionResult,
7
- buildRalphSystemMessage,
8
- createRalphState,
9
- deactivateRalphState,
10
- deleteRalphState,
11
- detectCompletionPromise,
12
- getRalphStatePath,
13
- loadRalphState,
14
- parseRalphState,
15
- updateRalphIteration,
16
- } from "../src/ralph-loop.js";
17
-
18
- let tempDir: string;
19
-
20
- beforeEach(() => {
21
- tempDir = path.join(tmpdir(), `ralph-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
22
- mkdirSync(tempDir, { recursive: true });
23
- });
24
-
25
- afterEach(() => {
26
- try {
27
- const { rmSync } = require("node:fs");
28
- rmSync(tempDir, { recursive: true, force: true });
29
- } catch {
30
- // Ignore cleanup errors on Windows
31
- }
32
- });
33
-
34
- describe("getRalphStatePath", () => {
35
- it("follows expected format", () => {
36
- const result = getRalphStatePath("workflow-123", "apply-fixes", tempDir);
37
- const expected = path.join(
38
- tempDir,
39
- "agentic",
40
- "outputs",
41
- "workflow-123",
42
- "ralph-apply-fixes.md",
43
- );
44
- expect(result).toBe(expected);
45
- });
46
-
47
- it("sanitizes special characters in step name", () => {
48
- const result = getRalphStatePath("workflow", "step/with:special@chars", tempDir);
49
- const filename = path.basename(result);
50
- expect(filename).not.toContain("/");
51
- expect(filename).not.toContain(":");
52
- expect(filename).not.toContain("@");
53
- });
54
- });
55
-
56
- describe("createRalphState", () => {
57
- it("creates basic ralph state", () => {
58
- const state = createRalphState(
59
- "test-workflow",
60
- "apply-fixes",
61
- "Fix the issues",
62
- 10,
63
- "FIXES_COMPLETE",
64
- tempDir,
65
- );
66
-
67
- expect(state.active).toBe(true);
68
- expect(state.iteration).toBe(1);
69
- expect(state.maxIterations).toBe(10);
70
- expect(state.completionPromise).toBe("FIXES_COMPLETE");
71
- expect(state.prompt).toBe("Fix the issues");
72
- expect(state.startedAt).toBeTruthy();
73
- });
74
-
75
- it("saves file to disk", () => {
76
- createRalphState("save-test", "test-step", "Test prompt", 5, "DONE", tempDir);
77
-
78
- const statePath = getRalphStatePath("save-test", "test-step", tempDir);
79
- expect(existsSync(statePath)).toBe(true);
80
- const content = readFileSync(statePath, "utf-8");
81
- expect(content).toContain("active: true");
82
- expect(content).toContain("iteration: 1");
83
- });
84
- });
85
-
86
- describe("loadRalphState", () => {
87
- it("loads existing ralph state", () => {
88
- createRalphState("load-test", "test-step", "Original prompt", 10, "COMPLETE", tempDir);
89
-
90
- const loaded = loadRalphState("load-test", "test-step", tempDir);
91
-
92
- expect(loaded).not.toBeNull();
93
- expect(loaded?.active).toBe(true);
94
- expect(loaded?.iteration).toBe(1);
95
- expect(loaded?.maxIterations).toBe(10);
96
- expect(loaded?.completionPromise).toBe("COMPLETE");
97
- expect(loaded?.prompt).toBe("Original prompt");
98
- });
99
-
100
- it("returns null for nonexistent state", () => {
101
- expect(loadRalphState("nonexistent", "step", tempDir)).toBeNull();
102
- });
103
- });
104
-
105
- describe("updateRalphIteration", () => {
106
- it("increments iteration counter", () => {
107
- createRalphState("update-test", "test-step", "Test", 10, "DONE", tempDir);
108
-
109
- const state = updateRalphIteration("update-test", "test-step", tempDir);
110
-
111
- expect(state).not.toBeNull();
112
- expect(state?.iteration).toBe(2);
113
- });
114
-
115
- it("persists iteration update to file", () => {
116
- createRalphState("persist-test", "test-step", "Test", 10, "DONE", tempDir);
117
-
118
- updateRalphIteration("persist-test", "test-step", tempDir);
119
- const loaded = loadRalphState("persist-test", "test-step", tempDir);
120
-
121
- expect(loaded).not.toBeNull();
122
- expect(loaded?.iteration).toBe(2);
123
- });
124
-
125
- it("returns null for nonexistent state", () => {
126
- expect(updateRalphIteration("nonexistent", "step", tempDir)).toBeNull();
127
- });
128
- });
129
-
130
- describe("deactivateRalphState", () => {
131
- it("deactivates ralph state", () => {
132
- createRalphState("deactivate-test", "test-step", "Test", 10, "DONE", tempDir);
133
-
134
- deactivateRalphState("deactivate-test", "test-step", tempDir);
135
- const loaded = loadRalphState("deactivate-test", "test-step", tempDir);
136
-
137
- expect(loaded).not.toBeNull();
138
- expect(loaded?.active).toBe(false);
139
- });
140
- });
141
-
142
- describe("deleteRalphState", () => {
143
- it("deletes ralph state file", () => {
144
- createRalphState("delete-test", "test-step", "Test", 10, "DONE", tempDir);
145
-
146
- const statePath = getRalphStatePath("delete-test", "test-step", tempDir);
147
- expect(existsSync(statePath)).toBe(true);
148
-
149
- deleteRalphState("delete-test", "test-step", tempDir);
150
- expect(existsSync(statePath)).toBe(false);
151
- });
152
-
153
- it("does not throw for nonexistent state", () => {
154
- expect(() => deleteRalphState("nonexistent", "step", tempDir)).not.toThrow();
155
- });
156
- });
157
-
158
- describe("parseRalphState", () => {
159
- it("parses valid markdown with frontmatter", () => {
160
- const content = `---
161
- active: true
162
- iteration: 3
163
- max_iterations: 10
164
- completion_promise: COMPLETE
165
- started_at: "2026-01-11T14:30:00Z"
166
- ---
167
-
168
- # Ralph Loop Prompt
169
-
170
- Fix all the bugs in the codebase.
171
- `;
172
- const state = parseRalphState(content);
173
-
174
- expect(state).not.toBeNull();
175
- expect(state?.active).toBe(true);
176
- expect(state?.iteration).toBe(3);
177
- expect(state?.maxIterations).toBe(10);
178
- expect(state?.completionPromise).toBe("COMPLETE");
179
- expect(state?.prompt).toBe("Fix all the bugs in the codebase.");
180
- });
181
-
182
- it("returns null for content without frontmatter", () => {
183
- expect(parseRalphState("Just plain text without frontmatter")).toBeNull();
184
- });
185
-
186
- it("parses incomplete frontmatter with defaults", () => {
187
- const content = `---
188
- active: true
189
- ---`;
190
- const state = parseRalphState(content);
191
- expect(state).not.toBeNull();
192
- expect(state?.active).toBe(true);
193
- expect(state?.iteration).toBe(1);
194
- expect(state?.maxIterations).toBe(5);
195
- });
196
- });
197
-
198
- describe("detectCompletionPromise", () => {
199
- it("detects completion in JSON code block", () => {
200
- const output = `
201
- I've completed the task.
202
-
203
- \`\`\`json
204
- {
205
- "ralph_complete": true,
206
- "promise": "COMPLETED"
207
- }
208
- \`\`\`
209
- `;
210
- const result = detectCompletionPromise(output, "COMPLETED");
211
- expect(result.isComplete).toBe(true);
212
- expect(result.promiseMatched).toBe(true);
213
- expect(result.promiseValue).toBe("COMPLETED");
214
- });
215
-
216
- it("detects completion in plain code block", () => {
217
- const output = `
218
- Done!
219
-
220
- \`\`\`
221
- {"ralph_complete": true, "promise": "DONE"}
222
- \`\`\`
223
- `;
224
- const result = detectCompletionPromise(output, "DONE");
225
- expect(result.isComplete).toBe(true);
226
- expect(result.promiseMatched).toBe(true);
227
- });
228
-
229
- it("detects completion in raw JSON", () => {
230
- const output = 'The task is done. {"ralph_complete": true, "promise": "FINISHED"}';
231
- const result = detectCompletionPromise(output, "FINISHED");
232
- expect(result.isComplete).toBe(true);
233
- expect(result.promiseMatched).toBe(true);
234
- });
235
-
236
- it("detects wrong promise value", () => {
237
- const output = `
238
- \`\`\`json
239
- {"ralph_complete": true, "promise": "WRONG_PROMISE"}
240
- \`\`\`
241
- `;
242
- const result = detectCompletionPromise(output, "EXPECTED_PROMISE");
243
- expect(result.isComplete).toBe(true);
244
- expect(result.promiseMatched).toBe(false);
245
- expect(result.promiseValue).toBe("WRONG_PROMISE");
246
- });
247
-
248
- it("detects ralph_complete: false as not complete", () => {
249
- const output = `
250
- \`\`\`json
251
- {"ralph_complete": false, "promise": "DONE"}
252
- \`\`\`
253
- `;
254
- const result = detectCompletionPromise(output, "DONE");
255
- expect(result.isComplete).toBe(false);
256
- expect(result.promiseMatched).toBe(false);
257
- });
258
-
259
- it("returns not complete for output without JSON", () => {
260
- const result = detectCompletionPromise("Just some regular output", "DONE");
261
- expect(result.isComplete).toBe(false);
262
- expect(result.promiseMatched).toBe(false);
263
- expect(result.promiseValue).toBeNull();
264
- });
265
-
266
- it("matches promise case-insensitively", () => {
267
- const output = '{"ralph_complete": true, "promise": "completed"}';
268
- const result = detectCompletionPromise(output, "COMPLETED");
269
- expect(result.isComplete).toBe(true);
270
- expect(result.promiseMatched).toBe(true);
271
- });
272
-
273
- it("handles invalid JSON gracefully", () => {
274
- const output = `
275
- \`\`\`json
276
- {invalid json here}
277
- \`\`\`
278
- `;
279
- const result = detectCompletionPromise(output, "DONE");
280
- expect(result.isComplete).toBe(false);
281
- });
282
-
283
- it("preserves original output in result", () => {
284
- const output = "Full output text here";
285
- const result = detectCompletionPromise(output, "DONE");
286
- expect(result.output).toBe(output);
287
- });
288
-
289
- it("detects failure signal in JSON code block", () => {
290
- const output = `
291
- I cannot complete the task due to permission errors.
292
-
293
- \`\`\`json
294
- {
295
- "ralph_failed": true,
296
- "reason": "Permission denied: cannot write to file"
297
- }
298
- \`\`\`
299
- `;
300
- const result = detectCompletionPromise(output, "COMPLETED");
301
- expect(result.isComplete).toBe(true);
302
- expect(result.isFailed).toBe(true);
303
- expect(result.promiseMatched).toBe(false);
304
- expect(result.failureReason).toBe("Permission denied: cannot write to file");
305
- });
306
-
307
- it("detects failure signal in raw JSON", () => {
308
- const output = 'Cannot proceed. {"ralph_failed": true, "reason": "Access denied"}';
309
- const result = detectCompletionPromise(output, "DONE");
310
- expect(result.isComplete).toBe(true);
311
- expect(result.isFailed).toBe(true);
312
- expect(result.failureReason).toBe("Access denied");
313
- });
314
-
315
- it("uses default reason for failure without reason field", () => {
316
- const output = '{"ralph_failed": true}';
317
- const result = detectCompletionPromise(output, "DONE");
318
- expect(result.isComplete).toBe(true);
319
- expect(result.isFailed).toBe(true);
320
- expect(result.failureReason).toBe("Unknown error");
321
- });
322
-
323
- it("prefers completion over failure when both present", () => {
324
- const output = `
325
- \`\`\`json
326
- {"ralph_complete": true, "promise": "DONE"}
327
- \`\`\`
328
- Also has failure:
329
- \`\`\`json
330
- {"ralph_failed": true, "reason": "Some error"}
331
- \`\`\`
332
- `;
333
- const result = detectCompletionPromise(output, "DONE");
334
- expect(result.isComplete).toBe(true);
335
- expect(result.promiseMatched).toBe(true);
336
- expect(result.isFailed).toBe(false);
337
- });
338
- });
339
-
340
- describe("buildRalphSystemMessage", () => {
341
- it("formats system message correctly", () => {
342
- const message = buildRalphSystemMessage(3, 10, "COMPLETE");
343
- expect(message).toContain("Iteration 3/10");
344
- expect(message).toContain("COMPLETE");
345
- expect(message).toContain("ralph_complete");
346
- expect(message).toContain("7 iterations remaining");
347
- });
348
-
349
- it("handles first iteration", () => {
350
- const message = buildRalphSystemMessage(1, 5, "DONE");
351
- expect(message).toContain("Iteration 1/5");
352
- expect(message).toContain("4 iterations remaining");
353
- });
354
-
355
- it("handles last iteration", () => {
356
- const message = buildRalphSystemMessage(10, 10, "FINISHED");
357
- expect(message).toContain("Iteration 10/10");
358
- expect(message).toContain("0 iterations remaining");
359
- });
360
-
361
- it("includes failure signal instructions", () => {
362
- const message = buildRalphSystemMessage(1, 5, "DONE");
363
- expect(message).toContain("ralph_failed");
364
- expect(message).toContain("Failure Signal");
365
- expect(message.toLowerCase()).toContain("permission errors");
366
- });
367
- });
368
-
369
- describe("CompletionResult", () => {
370
- it("supports default values", () => {
371
- const result: CompletionResult = {
372
- isComplete: false,
373
- promiseMatched: false,
374
- promiseValue: null,
375
- output: "test output",
376
- isFailed: false,
377
- failureReason: null,
378
- };
379
-
380
- expect(result.isComplete).toBe(false);
381
- expect(result.promiseMatched).toBe(false);
382
- expect(result.promiseValue).toBeNull();
383
- expect(result.output).toBe("test output");
384
- });
385
-
386
- it("supports success state", () => {
387
- const result: CompletionResult = {
388
- isComplete: true,
389
- promiseMatched: true,
390
- promiseValue: "DONE",
391
- output: "completed",
392
- isFailed: false,
393
- failureReason: null,
394
- };
395
-
396
- expect(result.isComplete).toBe(true);
397
- expect(result.promiseMatched).toBe(true);
398
- expect(result.promiseValue).toBe("DONE");
399
- expect(result.isFailed).toBe(false);
400
- expect(result.failureReason).toBeNull();
401
- });
402
-
403
- it("supports failure state", () => {
404
- const result: CompletionResult = {
405
- isComplete: true,
406
- promiseMatched: false,
407
- promiseValue: null,
408
- output: "failed output",
409
- isFailed: true,
410
- failureReason: "Permission denied",
411
- };
412
-
413
- expect(result.isComplete).toBe(true);
414
- expect(result.isFailed).toBe(true);
415
- expect(result.failureReason).toBe("Permission denied");
416
- expect(result.promiseMatched).toBe(false);
417
- });
418
- });