@ghostwater/soulforge 0.4.0 → 0.6.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.
@@ -0,0 +1,174 @@
1
+ # Soulforge Bugfix Workflow
2
+ # Diagnose → human review → fix → verify → PR
3
+ id: bugfix
4
+ name: Bug Fix
5
+ version: 1
6
+ description: |
7
+ Surgical bugfix pipeline. Diagnoses the bug and writes a failing test first,
8
+ then waits for human approval before implementing the fix.
9
+ Keeps scope tight — no "while I'm here" improvements.
10
+
11
+ defaults:
12
+ executor: claude-code
13
+ model: opus
14
+ timeout: 600
15
+ max_retries: 2
16
+ notify: [on_complete, on_fail]
17
+
18
+ steps:
19
+ - id: diagnose
20
+ executor: claude-code
21
+ model: opus
22
+ workdir: "{{workdir}}"
23
+ input: |
24
+ You are working in {{workdir}}. Diagnose the following bug.
25
+
26
+ BUG REPORT:
27
+ {{task}}
28
+
29
+ Instructions:
30
+ 1. Read the bug report carefully
31
+ 2. Explore the codebase to find the affected area
32
+ 3. Reproduce the bug: find or write a test that FAILS due to this bug
33
+ 4. Trace to root cause — understand exactly WHY it fails
34
+ 5. Propose a minimal fix (what files change, what the change is, why it works)
35
+
36
+ IMPORTANT:
37
+ - You MUST have a failing test before you can claim diagnosis is complete
38
+ - Do NOT implement the fix yet — only diagnose and propose
39
+ - Keep the fix proposal minimal — bugfixes should be surgical
40
+ - Commit the failing test: test: failing test for {{task}}
41
+
42
+ Reply with:
43
+ STATUS: done
44
+ AFFECTED_FILES: which files are involved
45
+ ROOT_CAUSE: exactly what's wrong and why
46
+ FAILING_TEST: what test you wrote and how it demonstrates the bug
47
+ FIX_PROPOSAL: what needs to change (be specific — file, function, what changes)
48
+ SCOPE: list of files that will be modified in the fix (max)
49
+ expects: "STATUS: done"
50
+
51
+ - id: review-diagnosis
52
+ executor: self
53
+ notify: on_waiting
54
+ on_reject:
55
+ reset_to: diagnose
56
+ input: |
57
+ Review the diagnosis before any fix is implemented.
58
+
59
+ BUG: {{task}}
60
+ ROOT CAUSE: {{root_cause}}
61
+ FAILING TEST: {{failing_test}}
62
+ FIX PROPOSAL: {{fix_proposal}}
63
+ SCOPE: {{scope}}
64
+
65
+ Questions to consider:
66
+ - Is the root cause correct?
67
+ - Does the failing test actually prove the bug?
68
+ - Is the proposed fix minimal and surgical?
69
+ - Is the scope reasonable?
70
+
71
+ - id: fix
72
+ executor: claude-code
73
+ model: opus
74
+ workdir: "{{workdir}}"
75
+ input: |
76
+ Implement the approved fix for this bug.
77
+
78
+ WORKDIR: {{workdir}}
79
+ BUILD_CMD: {{build_cmd}}
80
+ TEST_CMD: {{test_cmd}}
81
+
82
+ BUG: {{task}}
83
+ ROOT CAUSE: {{root_cause}}
84
+ FIX PROPOSAL: {{fix_proposal}}
85
+ SCOPE: {{scope}}
86
+
87
+ Instructions:
88
+ 1. Implement the fix — ONLY the approved changes in SCOPE
89
+ 2. The failing test from the diagnose step MUST now pass
90
+ 3. Run the full test suite: {{test_cmd}}
91
+ 4. Run build: {{build_cmd}}
92
+ 5. All tests must pass — no regressions
93
+ 6. Commit: fix: {{task}}
94
+
95
+ DO NOT:
96
+ - Refactor unrelated code
97
+ - Add features
98
+ - Change files outside SCOPE unless absolutely necessary
99
+ - "Improve" things while you're in there
100
+
101
+ Reply with:
102
+ STATUS: done
103
+ CHANGES: exactly what you changed and why
104
+ TEST_RESULTS: full test suite results
105
+ expects: "STATUS: done"
106
+
107
+ - id: verify
108
+ executor: claude-code
109
+ model: opus
110
+ workdir: "{{workdir}}"
111
+ input: |
112
+ Verify the bugfix independently.
113
+
114
+ WORKDIR: {{workdir}}
115
+ TEST_CMD: {{test_cmd}}
116
+ BUILD_CMD: {{build_cmd}}
117
+
118
+ BUG: {{task}}
119
+ ROOT CAUSE: {{root_cause}}
120
+ CHANGES: {{changes}}
121
+ SCOPE: {{scope}}
122
+
123
+ Verify:
124
+ 1. Run {{test_cmd}} — all tests pass (including the new regression test)
125
+ 2. Run {{build_cmd}} — build succeeds
126
+ 3. Review the diff: are changes limited to SCOPE?
127
+ 4. Does the fix actually address the root cause (not just mask symptoms)?
128
+ 5. Are there any edge cases the fix misses?
129
+
130
+ Reply with:
131
+ STATUS: done
132
+ VERIFIED: what you confirmed
133
+ DIFF_REVIEW: summary of actual changes vs approved scope
134
+
135
+ Or if issues found:
136
+ STATUS: retry
137
+ ISSUES:
138
+ - What's wrong
139
+ expects: "STATUS: done"
140
+
141
+ - id: pr
142
+ executor: claude-code
143
+ model: opus
144
+ workdir: "{{workdir}}"
145
+ notify: on_complete
146
+ input: |
147
+ Create a pull request for this bugfix.
148
+
149
+ WORKDIR: {{workdir}}
150
+ BUG: {{task}}
151
+ ROOT_CAUSE: {{root_cause}}
152
+ CHANGES: {{changes}}
153
+
154
+ Create a PR with gh pr create. The PR body should include:
155
+ - What the bug was
156
+ - Root cause
157
+ - What the fix does
158
+ - Link to the issue if one exists
159
+
160
+ Reply with:
161
+ STATUS: done
162
+ PR: URL to the pull request
163
+ expects: "STATUS: done"
164
+
165
+ - id: final-review
166
+ executor: self
167
+ notify: on_waiting
168
+ input: |
169
+ Final review of the bugfix PR.
170
+ PR: {{pr}}
171
+ BUG: {{task}}
172
+ ROOT CAUSE: {{root_cause}}
173
+ CHANGES: {{changes}}
174
+ VERIFIED: {{verified}}
@@ -56,6 +56,7 @@ steps:
56
56
  executor: claude-code
57
57
  model: opus
58
58
  workdir: "{{workdir}}"
59
+ notify: [on_complete, on_fail]
59
60
  type: loop
60
61
  loop:
61
62
  over: stories
@@ -151,6 +152,7 @@ steps:
151
152
  executor: claude-code
152
153
  model: opus
153
154
  workdir: "{{workdir}}"
155
+ notify: on_complete
154
156
  input: |
155
157
  Create a pull request.
156
158
 
@@ -1,378 +0,0 @@
1
- import { describe, it, before, after, beforeEach } from "node:test";
2
- import assert from "node:assert";
3
- import { DatabaseSync } from "node:sqlite";
4
- import fs from "node:fs";
5
- import path from "node:path";
6
- import os from "node:os";
7
- // Test-specific database setup
8
- let testDb;
9
- let testDbPath;
10
- // We'll test resetToStep by directly testing the database operations
11
- // Since the actual functions use a singleton, we'll create test helpers
12
- function setupTestDb() {
13
- const testDir = fs.mkdtempSync(path.join(os.tmpdir(), "soulforge-test-"));
14
- testDbPath = path.join(testDir, "test.db");
15
- testDb = new DatabaseSync(testDbPath);
16
- testDb.exec("PRAGMA journal_mode=WAL");
17
- testDb.exec("PRAGMA foreign_keys=ON");
18
- // Create schema
19
- testDb.exec(`
20
- CREATE TABLE IF NOT EXISTS runs (
21
- id TEXT PRIMARY KEY,
22
- workflow_id TEXT NOT NULL,
23
- workflow_path TEXT NOT NULL,
24
- task TEXT NOT NULL,
25
- status TEXT NOT NULL DEFAULT 'pending',
26
- context TEXT NOT NULL DEFAULT '{}',
27
- callback TEXT,
28
- worktree TEXT,
29
- created_at TEXT NOT NULL,
30
- updated_at TEXT NOT NULL
31
- );
32
-
33
- CREATE TABLE IF NOT EXISTS steps (
34
- id TEXT PRIMARY KEY,
35
- run_id TEXT NOT NULL REFERENCES runs(id),
36
- step_id TEXT NOT NULL,
37
- executor TEXT NOT NULL DEFAULT 'openclaw',
38
- model TEXT,
39
- agent_id TEXT,
40
- step_index INTEGER NOT NULL,
41
- input_template TEXT NOT NULL,
42
- expects TEXT,
43
- status TEXT NOT NULL DEFAULT 'waiting',
44
- output TEXT,
45
- error TEXT,
46
- retry_count INTEGER DEFAULT 0,
47
- max_retries INTEGER DEFAULT 2,
48
- duration_ms INTEGER,
49
- type TEXT NOT NULL DEFAULT 'single',
50
- loop_config TEXT,
51
- current_story_id TEXT,
52
- triggered_by_loop_step_id TEXT,
53
- workdir TEXT,
54
- created_at TEXT NOT NULL,
55
- updated_at TEXT NOT NULL
56
- );
57
-
58
- CREATE TABLE IF NOT EXISTS stories (
59
- id TEXT PRIMARY KEY,
60
- run_id TEXT NOT NULL REFERENCES runs(id),
61
- story_index INTEGER NOT NULL,
62
- story_id TEXT NOT NULL,
63
- title TEXT NOT NULL,
64
- description TEXT NOT NULL,
65
- acceptance_criteria TEXT NOT NULL,
66
- status TEXT NOT NULL DEFAULT 'pending',
67
- output TEXT,
68
- retry_count INTEGER DEFAULT 0,
69
- max_retries INTEGER DEFAULT 2,
70
- created_at TEXT NOT NULL,
71
- updated_at TEXT NOT NULL
72
- );
73
-
74
- CREATE TABLE IF NOT EXISTS events (
75
- id INTEGER PRIMARY KEY AUTOINCREMENT,
76
- run_id TEXT NOT NULL,
77
- step_id TEXT,
78
- type TEXT NOT NULL,
79
- summary TEXT NOT NULL,
80
- details TEXT,
81
- created_at TEXT NOT NULL
82
- );
83
- `);
84
- return testDb;
85
- }
86
- function cleanupTestDb() {
87
- if (testDb) {
88
- try {
89
- testDb.close();
90
- }
91
- catch { }
92
- }
93
- if (testDbPath) {
94
- try {
95
- fs.unlinkSync(testDbPath);
96
- fs.rmdirSync(path.dirname(testDbPath));
97
- }
98
- catch { }
99
- }
100
- }
101
- // resetToStep implementation for testing (mirrors the actual implementation)
102
- function resetToStep(db, runId, targetStepId, feedback) {
103
- const now = new Date().toISOString();
104
- // Get all steps for the run
105
- const steps = db.prepare("SELECT * FROM steps WHERE run_id = ? ORDER BY step_index ASC").all(runId);
106
- const targetStep = steps.find((s) => s.step_id === targetStepId);
107
- if (!targetStep) {
108
- throw new Error(`Target step "${targetStepId}" not found in run ${runId}`);
109
- }
110
- const targetIndex = targetStep.step_index;
111
- db.exec("BEGIN");
112
- try {
113
- // Set target step to 'pending'
114
- db.prepare("UPDATE steps SET status = 'pending', error = NULL, output = NULL, retry_count = 0, current_story_id = NULL, updated_at = ? WHERE run_id = ? AND step_index = ?").run(now, runId, targetIndex);
115
- // Set all steps after target to 'waiting'
116
- db.prepare("UPDATE steps SET status = 'waiting', error = NULL, output = NULL, retry_count = 0, current_story_id = NULL, updated_at = ? WHERE run_id = ? AND step_index > ?").run(now, runId, targetIndex);
117
- // Delete all stories for the run
118
- db.prepare("DELETE FROM stories WHERE run_id = ?").run(runId);
119
- // Update context with rejection_feedback
120
- const run = db.prepare("SELECT * FROM runs WHERE id = ?").get(runId);
121
- if (run) {
122
- const context = JSON.parse(run.context);
123
- context.rejection_feedback = feedback;
124
- db.prepare("UPDATE runs SET context = ?, status = 'running', updated_at = ? WHERE id = ?").run(JSON.stringify(context), now, runId);
125
- }
126
- db.exec("COMMIT");
127
- }
128
- catch (err) {
129
- db.exec("ROLLBACK");
130
- throw err;
131
- }
132
- }
133
- describe("resetToStep", () => {
134
- before(() => {
135
- setupTestDb();
136
- });
137
- after(() => {
138
- cleanupTestDb();
139
- });
140
- beforeEach(() => {
141
- // Clear tables before each test
142
- testDb.exec("DELETE FROM events");
143
- testDb.exec("DELETE FROM stories");
144
- testDb.exec("DELETE FROM steps");
145
- testDb.exec("DELETE FROM runs");
146
- });
147
- it("should set target step to pending", () => {
148
- const now = new Date().toISOString();
149
- const runId = "test-run-1";
150
- // Create test run
151
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", "{}", now, now);
152
- // Create test steps
153
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-1", runId, "analyze", 0, "input", "done", now, now);
154
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-2", runId, "implement", 1, "input", "done", now, now);
155
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-3", runId, "review-plan", 2, "input", "waiting_approval", now, now);
156
- // Reset to 'analyze' step
157
- resetToStep(testDb, runId, "analyze", "Plan needs revision");
158
- // Check target step is pending
159
- const targetStep = testDb.prepare("SELECT * FROM steps WHERE step_id = ?").get("analyze");
160
- assert.strictEqual(targetStep.status, "pending");
161
- });
162
- it("should set all steps after target to waiting", () => {
163
- const now = new Date().toISOString();
164
- const runId = "test-run-2";
165
- // Create test run
166
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", "{}", now, now);
167
- // Create test steps
168
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-1", runId, "analyze", 0, "input", "done", now, now);
169
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-2", runId, "implement", 1, "input", "done", now, now);
170
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-3", runId, "review-plan", 2, "input", "waiting_approval", now, now);
171
- // Reset to 'analyze' step
172
- resetToStep(testDb, runId, "analyze", "Plan needs revision");
173
- // Check steps after target are waiting
174
- const implementStep = testDb.prepare("SELECT * FROM steps WHERE step_id = ?").get("implement");
175
- const reviewStep = testDb.prepare("SELECT * FROM steps WHERE step_id = ?").get("review-plan");
176
- assert.strictEqual(implementStep.status, "waiting");
177
- assert.strictEqual(reviewStep.status, "waiting");
178
- });
179
- it("should delete all stories for the run", () => {
180
- const now = new Date().toISOString();
181
- const runId = "test-run-3";
182
- // Create test run
183
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", "{}", now, now);
184
- // Create test steps
185
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-1", runId, "analyze", 0, "input", "done", now, now);
186
- // Create test stories
187
- testDb.prepare("INSERT INTO stories (id, run_id, story_index, story_id, title, description, acceptance_criteria, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run("story-uuid-1", runId, 0, "story-1", "Story 1", "Description 1", "[]", "pending", now, now);
188
- testDb.prepare("INSERT INTO stories (id, run_id, story_index, story_id, title, description, acceptance_criteria, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run("story-uuid-2", runId, 1, "story-2", "Story 2", "Description 2", "[]", "done", now, now);
189
- // Verify stories exist
190
- const storiesBefore = testDb.prepare("SELECT COUNT(*) as count FROM stories WHERE run_id = ?").get(runId);
191
- assert.strictEqual(storiesBefore.count, 2);
192
- // Reset to 'analyze' step
193
- resetToStep(testDb, runId, "analyze", "Plan needs revision");
194
- // Check all stories deleted
195
- const storiesAfter = testDb.prepare("SELECT COUNT(*) as count FROM stories WHERE run_id = ?").get(runId);
196
- assert.strictEqual(storiesAfter.count, 0);
197
- });
198
- it("should update context with rejection_feedback", () => {
199
- const now = new Date().toISOString();
200
- const runId = "test-run-4";
201
- const feedback = "The plan is missing error handling";
202
- // Create test run with existing context
203
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", '{"existing_key":"value"}', now, now);
204
- // Create test step
205
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-1", runId, "analyze", 0, "input", "done", now, now);
206
- // Reset to 'analyze' step
207
- resetToStep(testDb, runId, "analyze", feedback);
208
- // Check context has rejection_feedback
209
- const run = testDb.prepare("SELECT * FROM runs WHERE id = ?").get(runId);
210
- const context = JSON.parse(run.context);
211
- assert.strictEqual(context.rejection_feedback, feedback);
212
- assert.strictEqual(context.existing_key, "value"); // Existing context preserved
213
- });
214
- it("should set run status to running", () => {
215
- const now = new Date().toISOString();
216
- const runId = "test-run-5";
217
- // Create test run with waiting_approval status
218
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "waiting_approval", "{}", now, now);
219
- // Create test step
220
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-1", runId, "analyze", 0, "input", "waiting_approval", now, now);
221
- // Reset to 'analyze' step
222
- resetToStep(testDb, runId, "analyze", "Needs work");
223
- // Check run status is running
224
- const run = testDb.prepare("SELECT * FROM runs WHERE id = ?").get(runId);
225
- assert.strictEqual(run.status, "running");
226
- });
227
- it("should throw error if target step not found", () => {
228
- const now = new Date().toISOString();
229
- const runId = "test-run-6";
230
- // Create test run
231
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", "{}", now, now);
232
- // Create test step
233
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-1", runId, "analyze", 0, "input", "done", now, now);
234
- // Try to reset to non-existent step
235
- assert.throws(() => resetToStep(testDb, runId, "non-existent-step", "Needs work"), /Target step "non-existent-step" not found/);
236
- });
237
- it("should reset retry_count and clear output/error on target step", () => {
238
- const now = new Date().toISOString();
239
- const runId = "test-run-7";
240
- // Create test run
241
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", "{}", now, now);
242
- // Create test step with retry_count, output, and error
243
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, output, error, retry_count, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run("step-uuid-1", runId, "analyze", 0, "input", "done", "some output", "some error", 2, now, now);
244
- // Reset to 'analyze' step
245
- resetToStep(testDb, runId, "analyze", "Needs work");
246
- // Check step has reset fields
247
- const step = testDb.prepare("SELECT * FROM steps WHERE step_id = ?").get("analyze");
248
- assert.strictEqual(step.retry_count, 0);
249
- assert.strictEqual(step.output, null);
250
- assert.strictEqual(step.error, null);
251
- });
252
- });
253
- describe("triggered_by_loop_step_id", () => {
254
- before(() => {
255
- setupTestDb();
256
- });
257
- after(() => {
258
- cleanupTestDb();
259
- });
260
- beforeEach(() => {
261
- // Clear tables before each test
262
- testDb.exec("DELETE FROM events");
263
- testDb.exec("DELETE FROM stories");
264
- testDb.exec("DELETE FROM steps");
265
- testDb.exec("DELETE FROM runs");
266
- });
267
- it("should store triggered_by_loop_step_id on verify step", () => {
268
- const now = new Date().toISOString();
269
- const runId = "test-run-loop-1";
270
- const loopStepId = "loop-step-uuid";
271
- const verifyStepId = "verify-step-uuid";
272
- // Create test run
273
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", "{}", now, now);
274
- // Create loop step
275
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, type, loop_config, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(loopStepId, runId, "implement", 0, "input", "running", "loop", '{"over":"stories","verifyEach":true,"verifyStep":"verify"}', now, now);
276
- // Create verify step without triggered_by_loop_step_id
277
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(verifyStepId, runId, "verify", 1, "input", "waiting", now, now);
278
- // Simulate loop step triggering verify step (set triggered_by_loop_step_id)
279
- testDb.prepare("UPDATE steps SET status = 'pending', triggered_by_loop_step_id = ?, updated_at = ? WHERE id = ?").run(loopStepId, now, verifyStepId);
280
- // Verify the triggered_by_loop_step_id is set
281
- const verifyStep = testDb.prepare("SELECT * FROM steps WHERE id = ?").get(verifyStepId);
282
- assert.strictEqual(verifyStep.triggered_by_loop_step_id, loopStepId);
283
- assert.strictEqual(verifyStep.status, "pending");
284
- });
285
- it("should clear triggered_by_loop_step_id after verify completes", () => {
286
- const now = new Date().toISOString();
287
- const runId = "test-run-loop-2";
288
- const loopStepId = "loop-step-uuid";
289
- const verifyStepId = "verify-step-uuid";
290
- // Create test run
291
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", "{}", now, now);
292
- // Create loop step
293
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, type, loop_config, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(loopStepId, runId, "implement", 0, "input", "running", "loop", '{"over":"stories","verifyEach":true,"verifyStep":"verify"}', now, now);
294
- // Create verify step with triggered_by_loop_step_id set (as if triggered by loop)
295
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, triggered_by_loop_step_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)").run(verifyStepId, runId, "verify", 1, "input", "pending", loopStepId, now, now);
296
- // Simulate verify step completing and clearing triggered_by_loop_step_id
297
- testDb.prepare("UPDATE steps SET status = 'done', triggered_by_loop_step_id = NULL, updated_at = ? WHERE id = ?").run(now, verifyStepId);
298
- // Verify the triggered_by_loop_step_id is cleared
299
- const verifyStep = testDb.prepare("SELECT * FROM steps WHERE id = ?").get(verifyStepId);
300
- assert.strictEqual(verifyStep.triggered_by_loop_step_id, null);
301
- assert.strictEqual(verifyStep.status, "done");
302
- });
303
- it("should set loop step back to pending when more stories remain", () => {
304
- const now = new Date().toISOString();
305
- const runId = "test-run-loop-3";
306
- const loopStepId = "loop-step-uuid";
307
- const verifyStepId = "verify-step-uuid";
308
- // Create test run
309
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", "{}", now, now);
310
- // Create loop step (running, processing first story)
311
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, type, loop_config, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(loopStepId, runId, "implement", 0, "input", "running", "loop", '{"over":"stories","completion":"all_done","verifyEach":true,"verifyStep":"verify"}', now, now);
312
- // Create verify step with triggered_by_loop_step_id
313
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, triggered_by_loop_step_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)").run(verifyStepId, runId, "verify", 1, "input", "pending", loopStepId, now, now);
314
- // Create stories - first is done, second is pending
315
- testDb.prepare("INSERT INTO stories (id, run_id, story_index, story_id, title, description, acceptance_criteria, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run("story-1-uuid", runId, 0, "story-1", "Story 1", "Description 1", "[]", "done", now, now);
316
- testDb.prepare("INSERT INTO stories (id, run_id, story_index, story_id, title, description, acceptance_criteria, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run("story-2-uuid", runId, 1, "story-2", "Story 2", "Description 2", "[]", "pending", now, now);
317
- // Simulate continueLoop behavior: check for next pending story
318
- const nextStory = testDb.prepare("SELECT * FROM stories WHERE run_id = ? AND status = 'pending' ORDER BY story_index ASC LIMIT 1").get(runId);
319
- assert.ok(nextStory, "There should be a pending story");
320
- assert.strictEqual(nextStory.story_id, "story-2");
321
- // Since there are more stories, loop step should go back to pending
322
- testDb.prepare("UPDATE steps SET status = 'pending', current_story_id = NULL, updated_at = ? WHERE id = ?").run(now, loopStepId);
323
- const loopStep = testDb.prepare("SELECT * FROM steps WHERE id = ?").get(loopStepId);
324
- assert.strictEqual(loopStep.status, "pending");
325
- });
326
- it("should mark loop step done when all stories complete", () => {
327
- const now = new Date().toISOString();
328
- const runId = "test-run-loop-4";
329
- const loopStepId = "loop-step-uuid";
330
- const verifyStepId = "verify-step-uuid";
331
- // Create test run
332
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", "{}", now, now);
333
- // Create loop step
334
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, type, loop_config, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(loopStepId, runId, "implement", 0, "input", "running", "loop", '{"over":"stories","completion":"all_done","verifyEach":true,"verifyStep":"verify"}', now, now);
335
- // Create verify step
336
- testDb.prepare("INSERT INTO steps (id, run_id, step_id, step_index, input_template, status, triggered_by_loop_step_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)").run(verifyStepId, runId, "verify", 1, "input", "pending", loopStepId, now, now);
337
- // Create stories - all done
338
- testDb.prepare("INSERT INTO stories (id, run_id, story_index, story_id, title, description, acceptance_criteria, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run("story-1-uuid", runId, 0, "story-1", "Story 1", "Description 1", "[]", "done", now, now);
339
- testDb.prepare("INSERT INTO stories (id, run_id, story_index, story_id, title, description, acceptance_criteria, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run("story-2-uuid", runId, 1, "story-2", "Story 2", "Description 2", "[]", "done", now, now);
340
- // Simulate continueLoop behavior: check for next pending story
341
- const nextStory = testDb.prepare("SELECT * FROM stories WHERE run_id = ? AND status = 'pending' ORDER BY story_index ASC LIMIT 1").get(runId);
342
- assert.ok(!nextStory, "There should be no pending stories");
343
- // Since no more stories, loop step should be marked done
344
- testDb.prepare("UPDATE steps SET status = 'done', updated_at = ? WHERE id = ?").run(now, loopStepId);
345
- const loopStep = testDb.prepare("SELECT * FROM steps WHERE id = ?").get(loopStepId);
346
- assert.strictEqual(loopStep.status, "done");
347
- });
348
- });
349
- describe("progress path", () => {
350
- const PROGRESS_DIR = path.join(os.homedir(), ".soulforge", "progress");
351
- it("should store progress outside worktree in ~/.soulforge/progress/", () => {
352
- const runId = "test-run-uuid-123";
353
- const expectedPath = path.join(PROGRESS_DIR, `${runId}.txt`);
354
- // Verify the path format is correct
355
- assert.ok(expectedPath.includes(".soulforge/progress"), "should be in ~/.soulforge/progress/");
356
- assert.ok(expectedPath.endsWith(`${runId}.txt`), "should be keyed by run ID");
357
- assert.ok(!expectedPath.includes("worktree"), "should NOT be inside a worktree");
358
- });
359
- it("should inject progress_path into run context", () => {
360
- // Check that createRun adds progress_path to initial context
361
- // by verifying the database schema includes it
362
- setupTestDb();
363
- const now = new Date().toISOString();
364
- const runId = "test-progress-run";
365
- const context = JSON.stringify({
366
- task: "test task",
367
- progress_path: path.join(PROGRESS_DIR, `${runId}.txt`),
368
- });
369
- testDb.prepare("INSERT INTO runs (id, workflow_id, workflow_path, task, status, context, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(runId, "test-workflow", "/path/to/workflow", "test task", "running", context, now, now);
370
- const run = testDb.prepare("SELECT * FROM runs WHERE id = ?").get(runId);
371
- const parsedContext = JSON.parse(run.context);
372
- assert.ok(parsedContext.progress_path, "progress_path should be in context");
373
- assert.ok(parsedContext.progress_path.includes(runId), "should include run ID");
374
- assert.ok(parsedContext.progress_path.includes("progress"), "should include progress dir");
375
- cleanupTestDb();
376
- });
377
- });
378
- //# sourceMappingURL=database.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"database.test.js","sourceRoot":"","sources":["../../src/db/database.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACpE,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,+BAA+B;AAC/B,IAAI,MAAoB,CAAC;AACzB,IAAI,UAAkB,CAAC;AAEvB,qEAAqE;AACrE,wEAAwE;AAExE,SAAS,WAAW;IAClB,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC1E,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC3C,MAAM,GAAG,IAAI,YAAY,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACvC,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAEtC,gBAAgB;IAChB,MAAM,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEX,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa;IACpB,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC;YACH,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IACD,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC;YACH,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;YAC1B,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,SAAS,WAAW,CAAC,EAAgB,EAAE,KAAa,EAAE,YAAoB,EAAE,QAAgB;IAC1F,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,4BAA4B;IAC5B,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CACtB,8DAA8D,CAC/D,CAAC,GAAG,CAAC,KAAK,CAAU,CAAC;IAEtB,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC;IACtE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,gBAAgB,YAAY,sBAAsB,KAAK,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC;IAE1C,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjB,IAAI,CAAC;QACH,+BAA+B;QAC/B,EAAE,CAAC,OAAO,CACR,gKAAgK,CACjK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;QAE/B,0CAA0C;QAC1C,EAAE,CAAC,OAAO,CACR,gKAAgK,CACjK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;QAE/B,iCAAiC;QACjC,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE9D,yCAAyC;QACzC,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAQ,CAAC;QAC5E,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACxC,OAAO,CAAC,kBAAkB,GAAG,QAAQ,CAAC;YACtC,EAAE,CAAC,OAAO,CACR,8EAA8E,CAC/E,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7C,CAAC;QAED,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpB,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,MAAM,CAAC,GAAG,EAAE;QACV,WAAW,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,GAAG,EAAE;QACT,aAAa,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,GAAG,EAAE;QACd,gCAAgC;QAChC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC;QAE3B,kBAAkB;QAClB,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE3F,oBAAoB;QACpB,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACrE,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACvE,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAErF,0BAA0B;QAC1B,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;QAE7D,+BAA+B;QAC/B,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAQ,CAAC;QACjG,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC;QAE3B,kBAAkB;QAClB,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE3F,oBAAoB;QACpB,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACrE,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACvE,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAErF,0BAA0B;QAC1B,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;QAE7D,uCAAuC;QACvC,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAQ,CAAC;QACtG,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAQ,CAAC;QACrG,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACpD,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC;QAE3B,kBAAkB;QAClB,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE3F,oBAAoB;QACpB,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAErE,sBAAsB;QACtB,MAAM,CAAC,OAAO,CACZ,wKAAwK,CACzK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAClG,MAAM,CAAC,OAAO,CACZ,wKAAwK,CACzK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE/F,uBAAuB;QACvB,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,wDAAwD,CAAC,CAAC,GAAG,CAAC,KAAK,CAAQ,CAAC;QACjH,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAE3C,0BAA0B;QAC1B,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;QAE7D,4BAA4B;QAC5B,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,wDAAwD,CAAC,CAAC,GAAG,CAAC,KAAK,CAAQ,CAAC;QAChH,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC;QAC3B,MAAM,QAAQ,GAAG,oCAAoC,CAAC;QAEtD,wCAAwC;QACxC,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,0BAA0B,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAEjH,mBAAmB;QACnB,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAErE,0BAA0B;QAC1B,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEhD,uCAAuC;QACvC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAQ,CAAC;QAChF,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;QACzD,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,6BAA6B;IAClF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC;QAE3B,+CAA+C;QAC/C,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAEpG,mBAAmB;QACnB,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAEjF,0BAA0B;QAC1B,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;QAEpD,8BAA8B;QAC9B,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAQ,CAAC;QAChF,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC;QAE3B,kBAAkB;QAClB,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE3F,mBAAmB;QACnB,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAErE,oCAAoC;QACpC,MAAM,CAAC,MAAM,CACX,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,mBAAmB,EAAE,YAAY,CAAC,EACnE,2CAA2C,CAC5C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC;QAE3B,kBAAkB;QAClB,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE3F,uDAAuD;QACvD,MAAM,CAAC,OAAO,CACZ,0KAA0K,CAC3K,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAErG,0BAA0B;QAC1B,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;QAEpD,8BAA8B;QAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAQ,CAAC;QAC3F,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACtC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,MAAM,CAAC,GAAG,EAAE;QACV,WAAW,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,GAAG,EAAE;QACT,aAAa,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,GAAG,EAAE;QACd,gCAAgC;QAChC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,iBAAiB,CAAC;QAChC,MAAM,UAAU,GAAG,gBAAgB,CAAC;QACpC,MAAM,YAAY,GAAG,kBAAkB,CAAC;QAExC,kBAAkB;QAClB,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE3F,mBAAmB;QACnB,MAAM,CAAC,OAAO,CACZ,8JAA8J,CAC/J,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,4DAA4D,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE7I,uDAAuD;QACvD,MAAM,CAAC,OAAO,CACZ,qIAAqI,CACtI,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAEtE,4EAA4E;QAC5E,MAAM,CAAC,OAAO,CACZ,iGAAiG,CAClG,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;QAErC,8CAA8C;QAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAQ,CAAC;QAC/F,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,yBAAyB,EAAE,UAAU,CAAC,CAAC;QACrE,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,iBAAiB,CAAC;QAChC,MAAM,UAAU,GAAG,gBAAgB,CAAC;QACpC,MAAM,YAAY,GAAG,kBAAkB,CAAC;QAExC,kBAAkB;QAClB,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE3F,mBAAmB;QACnB,MAAM,CAAC,OAAO,CACZ,8JAA8J,CAC/J,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,4DAA4D,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE7I,kFAAkF;QAClF,MAAM,CAAC,OAAO,CACZ,mKAAmK,CACpK,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAElF,yEAAyE;QACzE,MAAM,CAAC,OAAO,CACZ,iGAAiG,CAClG,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QAEzB,kDAAkD;QAClD,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAQ,CAAC;QAC/F,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,yBAAyB,EAAE,IAAI,CAAC,CAAC;QAC/D,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,iBAAiB,CAAC;QAChC,MAAM,UAAU,GAAG,gBAAgB,CAAC;QACpC,MAAM,YAAY,GAAG,kBAAkB,CAAC;QAExC,kBAAkB;QAClB,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE3F,qDAAqD;QACrD,MAAM,CAAC,OAAO,CACZ,8JAA8J,CAC/J,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,oFAAoF,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAErK,oDAAoD;QACpD,MAAM,CAAC,OAAO,CACZ,mKAAmK,CACpK,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAElF,oDAAoD;QACpD,MAAM,CAAC,OAAO,CACZ,wKAAwK,CACzK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC/F,MAAM,CAAC,OAAO,CACZ,wKAAwK,CACzK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAElG,+DAA+D;QAC/D,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAC9B,gGAAgG,CACjG,CAAC,GAAG,CAAC,KAAK,CAAQ,CAAC;QAEpB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,iCAAiC,CAAC,CAAC;QACxD,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAElD,oEAAoE;QACpE,MAAM,CAAC,OAAO,CACZ,2FAA2F,CAC5F,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAEvB,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAQ,CAAC;QAC3F,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,iBAAiB,CAAC;QAChC,MAAM,UAAU,GAAG,gBAAgB,CAAC;QACpC,MAAM,YAAY,GAAG,kBAAkB,CAAC;QAExC,kBAAkB;QAClB,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE3F,mBAAmB;QACnB,MAAM,CAAC,OAAO,CACZ,8JAA8J,CAC/J,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,oFAAoF,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAErK,qBAAqB;QACrB,MAAM,CAAC,OAAO,CACZ,mKAAmK,CACpK,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAElF,4BAA4B;QAC5B,MAAM,CAAC,OAAO,CACZ,wKAAwK,CACzK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC/F,MAAM,CAAC,OAAO,CACZ,wKAAwK,CACzK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE/F,+DAA+D;QAC/D,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAC9B,gGAAgG,CACjG,CAAC,GAAG,CAAC,KAAK,CAAQ,CAAC;QAEpB,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,oCAAoC,CAAC,CAAC;QAE5D,yDAAyD;QACzD,MAAM,CAAC,OAAO,CACZ,+DAA+D,CAChE,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAEvB,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAQ,CAAC;QAC3F,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;IAEvE,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,KAAK,GAAG,mBAAmB,CAAC;QAClC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,KAAK,MAAM,CAAC,CAAC;QAC7D,oCAAoC;QACpC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,qCAAqC,CAAC,CAAC;QAC/F,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,KAAK,MAAM,CAAC,EAAE,2BAA2B,CAAC,CAAC;QAC9E,MAAM,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,iCAAiC,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,6DAA6D;QAC7D,+CAA+C;QAC/C,WAAW,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,mBAAmB,CAAC;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;YAC7B,IAAI,EAAE,WAAW;YACjB,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,KAAK,MAAM,CAAC;SACvD,CAAC,CAAC;QAEH,MAAM,CAAC,OAAO,CACZ,kIAAkI,CACnI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE9F,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAQ,CAAC;QAChF,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,aAAa,EAAE,oCAAoC,CAAC,CAAC;QAC7E,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,uBAAuB,CAAC,CAAC;QAChF,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,6BAA6B,CAAC,CAAC;QAC3F,aAAa,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
File without changes