@stackmemoryai/stackmemory 0.3.21 → 0.3.24

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 (66) hide show
  1. package/dist/cli/commands/linear-unified.js +2 -3
  2. package/dist/cli/commands/linear-unified.js.map +2 -2
  3. package/dist/cli/commands/ralph.js +294 -0
  4. package/dist/cli/commands/ralph.js.map +7 -0
  5. package/dist/cli/commands/tasks.js +1 -1
  6. package/dist/cli/commands/tasks.js.map +2 -2
  7. package/dist/cli/index.js +2 -0
  8. package/dist/cli/index.js.map +2 -2
  9. package/dist/integrations/mcp/handlers/code-execution-handlers.js +262 -0
  10. package/dist/integrations/mcp/handlers/code-execution-handlers.js.map +7 -0
  11. package/dist/integrations/mcp/tool-definitions-code.js +121 -0
  12. package/dist/integrations/mcp/tool-definitions-code.js.map +7 -0
  13. package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js +586 -0
  14. package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js.map +7 -0
  15. package/dist/integrations/ralph/context/context-budget-manager.js +297 -0
  16. package/dist/integrations/ralph/context/context-budget-manager.js.map +7 -0
  17. package/dist/integrations/ralph/context/stackmemory-context-loader.js +356 -0
  18. package/dist/integrations/ralph/context/stackmemory-context-loader.js.map +7 -0
  19. package/dist/integrations/ralph/index.js +14 -0
  20. package/dist/integrations/ralph/index.js.map +7 -0
  21. package/dist/integrations/ralph/learning/pattern-learner.js +397 -0
  22. package/dist/integrations/ralph/learning/pattern-learner.js.map +7 -0
  23. package/dist/integrations/ralph/lifecycle/iteration-lifecycle.js +444 -0
  24. package/dist/integrations/ralph/lifecycle/iteration-lifecycle.js.map +7 -0
  25. package/dist/integrations/ralph/orchestration/multi-loop-orchestrator.js +459 -0
  26. package/dist/integrations/ralph/orchestration/multi-loop-orchestrator.js.map +7 -0
  27. package/dist/integrations/ralph/performance/performance-optimizer.js +354 -0
  28. package/dist/integrations/ralph/performance/performance-optimizer.js.map +7 -0
  29. package/dist/integrations/ralph/ralph-integration-demo.js +178 -0
  30. package/dist/integrations/ralph/ralph-integration-demo.js.map +7 -0
  31. package/dist/integrations/ralph/state/state-reconciler.js +400 -0
  32. package/dist/integrations/ralph/state/state-reconciler.js.map +7 -0
  33. package/dist/integrations/ralph/swarm/swarm-coordinator.js +487 -0
  34. package/dist/integrations/ralph/swarm/swarm-coordinator.js.map +7 -0
  35. package/dist/integrations/ralph/types.js +1 -0
  36. package/dist/integrations/ralph/types.js.map +7 -0
  37. package/dist/integrations/ralph/visualization/ralph-debugger.js +581 -0
  38. package/dist/integrations/ralph/visualization/ralph-debugger.js.map +7 -0
  39. package/dist/servers/railway/index.js +98 -92
  40. package/dist/servers/railway/index.js.map +3 -3
  41. package/package.json +1 -2
  42. package/scripts/claude-sm-autostart.js +1 -1
  43. package/scripts/clean-linear-backlog.js +2 -2
  44. package/scripts/debug-linear-update.js +1 -1
  45. package/scripts/debug-railway-build.js +87 -0
  46. package/scripts/delete-linear-tasks.js +2 -2
  47. package/scripts/deploy-ralph-swarm.sh +365 -0
  48. package/scripts/install-code-execution-hooks.sh +96 -0
  49. package/scripts/linear-task-review.js +1 -1
  50. package/scripts/ralph-integration-test.js +274 -0
  51. package/scripts/ralph-loop-implementation.js +404 -0
  52. package/scripts/swarm-monitor.js +509 -0
  53. package/scripts/sync-and-clean-tasks.js +1 -1
  54. package/scripts/sync-linear-graphql.js +3 -3
  55. package/scripts/sync-linear-tasks.js +1 -1
  56. package/scripts/test-code-execution.js +143 -0
  57. package/scripts/test-parallel-swarms.js +443 -0
  58. package/scripts/testing/ralph-cli-test.js +88 -0
  59. package/scripts/testing/ralph-integration-validation.js +727 -0
  60. package/scripts/testing/ralph-swarm-test-scenarios.js +613 -0
  61. package/scripts/update-linear-tasks-fixed.js +1 -1
  62. package/scripts/validate-railway-deployment.js +137 -0
  63. package/templates/claude-hooks/hook-config.json +59 -0
  64. package/templates/claude-hooks/pre-tool-use +189 -0
  65. package/dist/servers/railway/minimal.js +0 -91
  66. package/dist/servers/railway/minimal.js.map +0 -7
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Ralph-StackMemory Integration Test Script
5
+ * Simple CLI to test the integration functionality
6
+ */
7
+
8
+ import { RalphIntegrationDemo } from '../dist/integrations/ralph/ralph-integration-demo.js';
9
+ import { performance } from 'perf_hooks';
10
+
11
+ async function main() {
12
+ const args = process.argv.slice(2);
13
+ const command = args[0] || 'demo';
14
+
15
+ console.log('\n🧪 Ralph-StackMemory Integration Test');
16
+ console.log('=====================================\n');
17
+
18
+ const startTime = performance.now();
19
+
20
+ try {
21
+ switch (command) {
22
+ case 'demo':
23
+ await runDemo();
24
+ break;
25
+ case 'quick':
26
+ await runQuickTest();
27
+ break;
28
+ case 'validate':
29
+ await runValidation();
30
+ break;
31
+ default:
32
+ showUsage();
33
+ return;
34
+ }
35
+
36
+ const endTime = performance.now();
37
+ const duration = Math.round(endTime - startTime);
38
+
39
+ console.log(`\n✅ Test completed successfully in ${duration}ms`);
40
+
41
+ } catch (error) {
42
+ console.error(`\n❌ Test failed: ${error.message}`);
43
+
44
+ if (process.env.DEBUG) {
45
+ console.error('\nDebug info:');
46
+ console.error(error.stack);
47
+ }
48
+
49
+ process.exit(1);
50
+ }
51
+ }
52
+
53
+ async function runDemo() {
54
+ console.log('🎬 Running full integration demo...\n');
55
+
56
+ const demo = new RalphIntegrationDemo();
57
+ await demo.run();
58
+ }
59
+
60
+ async function runQuickTest() {
61
+ console.log('⚡ Running quick validation test...\n');
62
+
63
+ // Import the core classes to test they load correctly
64
+ try {
65
+ await import('../dist/integrations/ralph/index.js');
66
+ console.log('✓ Core bridge class loaded');
67
+
68
+ const { ContextBudgetManager } = await import('../dist/integrations/ralph/index.js');
69
+ console.log('✓ Context budget manager loaded');
70
+
71
+ const { StateReconciler } = await import('../dist/integrations/ralph/index.js');
72
+ console.log('✓ State reconciler loaded');
73
+
74
+ await import('../dist/integrations/ralph/index.js');
75
+ console.log('✓ Iteration lifecycle loaded');
76
+
77
+ await import('../dist/integrations/ralph/index.js');
78
+ console.log('✓ Performance optimizer loaded');
79
+
80
+ // Test basic instantiation
81
+ const budgetManager = new ContextBudgetManager();
82
+ const tokenEstimate = budgetManager.estimateTokens('Hello, world!');
83
+ console.log(`✓ Token estimation working: ${tokenEstimate} tokens`);
84
+
85
+ new StateReconciler();
86
+ console.log('✓ State reconciler instantiated');
87
+
88
+ console.log('\n🎯 All core components validated successfully!');
89
+
90
+ } catch (error) {
91
+ throw new Error(`Component loading failed: ${error.message}`);
92
+ }
93
+ }
94
+
95
+ async function runValidation() {
96
+ console.log('🔍 Running detailed validation...\n');
97
+
98
+ // Test context budget manager
99
+ await testContextBudgetManager();
100
+
101
+ // Test state reconciler
102
+ await testStateReconciler();
103
+
104
+ // Test performance optimizer
105
+ await testPerformanceOptimizer();
106
+
107
+ console.log('\n✨ All validation tests passed!');
108
+ }
109
+
110
+ async function testContextBudgetManager() {
111
+ console.log('📊 Testing Context Budget Manager...');
112
+
113
+ const { ContextBudgetManager } = await import('../dist/integrations/ralph/index.js');
114
+
115
+ const manager = new ContextBudgetManager({
116
+ maxTokens: 100,
117
+ compressionEnabled: true
118
+ });
119
+
120
+ // Test token estimation
121
+ const shortText = 'Short text';
122
+ const longText = 'This is a much longer piece of text that should have more tokens estimated for it than the shorter version above.';
123
+
124
+ const shortTokens = manager.estimateTokens(shortText);
125
+ const longTokens = manager.estimateTokens(longText);
126
+
127
+ if (longTokens <= shortTokens) {
128
+ throw new Error('Token estimation not working correctly');
129
+ }
130
+
131
+ // Test empty text
132
+ const emptyTokens = manager.estimateTokens('');
133
+ if (emptyTokens !== 0) {
134
+ throw new Error('Empty text should have 0 tokens');
135
+ }
136
+
137
+ console.log(' ✓ Token estimation working correctly');
138
+
139
+ // Test usage tracking
140
+ const usage = manager.getUsage();
141
+ if (typeof usage.used !== 'number' || typeof usage.available !== 'number') {
142
+ throw new Error('Usage tracking not working');
143
+ }
144
+
145
+ console.log(' ✓ Usage tracking functional');
146
+ }
147
+
148
+ async function testStateReconciler() {
149
+ console.log('🔄 Testing State Reconciler...');
150
+
151
+ const { StateReconciler } = await import('../dist/integrations/ralph/index.js');
152
+
153
+ const reconciler = new StateReconciler({
154
+ precedence: ['git', 'files', 'memory'],
155
+ conflictResolution: 'automatic'
156
+ });
157
+
158
+ // Test conflict detection
159
+ const sources = [
160
+ {
161
+ type: 'git',
162
+ state: { iteration: 5, status: 'running' },
163
+ timestamp: Date.now(),
164
+ confidence: 0.9
165
+ },
166
+ {
167
+ type: 'files',
168
+ state: { iteration: 5, status: 'running' },
169
+ timestamp: Date.now(),
170
+ confidence: 0.95
171
+ }
172
+ ];
173
+
174
+ const conflicts = reconciler.detectConflicts(sources);
175
+ if (conflicts.length !== 0) {
176
+ throw new Error('Should not detect conflicts in matching sources');
177
+ }
178
+
179
+ console.log(' ✓ Conflict detection working');
180
+
181
+ // Test state sources
182
+ const gitState = await reconciler.getGitState();
183
+ const fileState = await reconciler.getFileState();
184
+ const memoryState = await reconciler.getMemoryState('test-loop');
185
+
186
+ if (gitState.type !== 'git' || fileState.type !== 'files' || memoryState.type !== 'memory') {
187
+ throw new Error('State source types incorrect');
188
+ }
189
+
190
+ console.log(' ✓ State source loading functional');
191
+ }
192
+
193
+ async function testPerformanceOptimizer() {
194
+ console.log('⚡ Testing Performance Optimizer...');
195
+
196
+ const { PerformanceOptimizer } = await import('../dist/integrations/ralph/index.js');
197
+
198
+ const optimizer = new PerformanceOptimizer({
199
+ asyncSaves: true,
200
+ compressionLevel: 1,
201
+ cacheEnabled: true
202
+ });
203
+
204
+ // Test metrics
205
+ const metrics = optimizer.getMetrics();
206
+ const requiredMetrics = ['iterationTime', 'contextLoadTime', 'stateSaveTime', 'memoryUsage', 'tokenCount', 'cacheHitRate'];
207
+
208
+ for (const metric of requiredMetrics) {
209
+ if (typeof metrics[metric] !== 'number') {
210
+ throw new Error(`Missing or invalid metric: ${metric}`);
211
+ }
212
+ }
213
+
214
+ console.log(' ✓ Performance metrics available');
215
+
216
+ // Test compression
217
+ const testData = { message: 'Hello, world!', array: [1, 2, 3, 4, 5] };
218
+ const compressed = await optimizer.compressData(testData);
219
+
220
+ if (compressed.compressed !== true) {
221
+ throw new Error('Data compression not working');
222
+ }
223
+
224
+ const decompressed = await optimizer.decompressData(compressed);
225
+ if (JSON.stringify(decompressed) !== JSON.stringify(testData)) {
226
+ throw new Error('Data decompression failed');
227
+ }
228
+
229
+ console.log(' ✓ Compression/decompression working');
230
+
231
+ // Cleanup
232
+ optimizer.cleanup();
233
+ }
234
+
235
+ function showUsage() {
236
+ console.log(`
237
+ Usage: node ralph-integration-test.js [command]
238
+
239
+ Commands:
240
+ demo Run the full integration demonstration (default)
241
+ quick Quick validation of core components
242
+ validate Detailed validation of all functionality
243
+
244
+ Examples:
245
+ node ralph-integration-test.js
246
+ node ralph-integration-test.js quick
247
+ DEBUG=1 node ralph-integration-test.js validate
248
+
249
+ Environment Variables:
250
+ DEBUG=1 Show detailed error information
251
+ `);
252
+ }
253
+
254
+ // Handle unhandled promise rejections
255
+ process.on('unhandledRejection', (reason, _promise) => {
256
+ console.error('\n💥 Unhandled Promise Rejection:');
257
+ console.error(reason);
258
+ process.exit(1);
259
+ });
260
+
261
+ // Handle uncaught exceptions
262
+ process.on('uncaughtException', (error) => {
263
+ console.error('\n💥 Uncaught Exception:');
264
+ console.error(error.message);
265
+ if (process.env.DEBUG) {
266
+ console.error(error.stack);
267
+ }
268
+ process.exit(1);
269
+ });
270
+
271
+ // Run if called directly
272
+ if (import.meta.url === `file://${process.argv[1]}`) {
273
+ main().catch(console.error);
274
+ }
@@ -0,0 +1,404 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { execSync } from 'child_process';
6
+ import { fileURLToPath } from 'url';
7
+
8
+ class RalphLoop {
9
+ constructor(options = {}) {
10
+ this.baseDir = options.baseDir || '.ralph';
11
+ this.maxIterations = options.maxIterations || 50;
12
+ this.verbose = options.verbose || false;
13
+
14
+ this.paths = {
15
+ task: path.join(this.baseDir, 'task.md'),
16
+ criteria: path.join(this.baseDir, 'completion-criteria.md'),
17
+ iteration: path.join(this.baseDir, 'iteration.txt'),
18
+ feedback: path.join(this.baseDir, 'feedback.txt'),
19
+ state: path.join(this.baseDir, 'state.json'),
20
+ complete: path.join(this.baseDir, 'work-complete.txt'),
21
+ progress: path.join(this.baseDir, 'progress.jsonl'),
22
+ history: path.join(this.baseDir, 'history')
23
+ };
24
+ }
25
+
26
+ async initialize(task, criteria) {
27
+ // Create directory structure
28
+ fs.mkdirSync(this.baseDir, { recursive: true });
29
+ fs.mkdirSync(this.paths.history, { recursive: true });
30
+
31
+ // Initialize files
32
+ fs.writeFileSync(this.paths.task, task);
33
+ fs.writeFileSync(this.paths.criteria, criteria);
34
+ fs.writeFileSync(this.paths.iteration, '0');
35
+ fs.writeFileSync(this.paths.feedback, '');
36
+
37
+ // Initial state
38
+ const state = {
39
+ startTime: Date.now(),
40
+ task: task.substring(0, 100),
41
+ status: 'initialized'
42
+ };
43
+ fs.writeFileSync(this.paths.state, JSON.stringify(state, null, 2));
44
+
45
+ this.log('Ralph Loop initialized');
46
+ }
47
+
48
+ async runWorkerIteration() {
49
+ const iteration = this.getCurrentIteration();
50
+ const task = fs.readFileSync(this.paths.task, 'utf8');
51
+ const feedback = this.getFeedback();
52
+
53
+ this.log(`Worker iteration ${iteration} starting...`);
54
+
55
+ // Step 1: Analyze current state (fresh context)
56
+ const analysis = await this.analyzeCurrentState();
57
+
58
+ // Step 2: Plan based on task and feedback
59
+ const plan = await this.createPlan(task, feedback, analysis);
60
+
61
+ // Step 3: Execute changes
62
+ const changes = await this.executeChanges(plan);
63
+
64
+ // Step 4: Validate changes
65
+ const validation = await this.validateChanges();
66
+
67
+ // Step 5: Save iteration artifacts
68
+ await this.saveIterationArtifacts(iteration, {
69
+ analysis,
70
+ plan,
71
+ changes,
72
+ validation
73
+ });
74
+
75
+ // Step 6: Commit changes
76
+ this.commitChanges(iteration, plan.summary);
77
+
78
+ return {
79
+ iteration,
80
+ changes: changes.length,
81
+ validation
82
+ };
83
+ }
84
+
85
+ async runReviewerIteration() {
86
+ const iteration = this.getCurrentIteration();
87
+ const task = fs.readFileSync(this.paths.task, 'utf8');
88
+ const criteria = fs.readFileSync(this.paths.criteria, 'utf8');
89
+
90
+ this.log(`Reviewer iteration ${iteration} evaluating...`);
91
+
92
+ // Fresh evaluation of current state
93
+ const evaluation = await this.evaluateAgainstCriteria(criteria);
94
+
95
+ if (evaluation.complete) {
96
+ fs.writeFileSync(this.paths.complete, 'true');
97
+ this.log('Task completed successfully!');
98
+ return { complete: true };
99
+ }
100
+
101
+ // Generate feedback for next iteration
102
+ const feedback = this.generateFeedback(evaluation);
103
+ fs.writeFileSync(this.paths.feedback, feedback);
104
+
105
+ // Increment iteration
106
+ this.incrementIteration();
107
+
108
+ return {
109
+ complete: false,
110
+ feedback: feedback.substring(0, 200)
111
+ };
112
+ }
113
+
114
+ async analyzeCurrentState() {
115
+ // Simulate fresh analysis of codebase
116
+ const files = this.scanRelevantFiles();
117
+ const tests = this.getTestStatus();
118
+ const lastCommit = this.getLastCommit();
119
+
120
+ return {
121
+ filesCount: files.length,
122
+ testsPass: tests.passing,
123
+ testsFail: tests.failing,
124
+ lastChange: lastCommit
125
+ };
126
+ }
127
+
128
+ async createPlan(_task, feedback, _analysis) {
129
+ // In real implementation, this would use an LLM
130
+ // Here we simulate planning based on feedback
131
+ const needsWork = feedback.includes('failing') ||
132
+ feedback.includes('incomplete') ||
133
+ feedback === '';
134
+
135
+ return {
136
+ summary: `Iteration work based on: ${feedback.substring(0, 50)}`,
137
+ steps: needsWork ? ['Fix issues', 'Add features', 'Update tests'] : ['Polish'],
138
+ priority: needsWork ? 'high' : 'low'
139
+ };
140
+ }
141
+
142
+ async executeChanges(plan) {
143
+ // Simulate making code changes
144
+ const changes = [];
145
+
146
+ for (const step of plan.steps) {
147
+ changes.push({
148
+ step,
149
+ timestamp: Date.now(),
150
+ result: 'simulated'
151
+ });
152
+ }
153
+
154
+ return changes;
155
+ }
156
+
157
+ async validateChanges() {
158
+ // Run tests and checks
159
+ try {
160
+ const testResult = this.runTests();
161
+ const lintResult = this.runLint();
162
+
163
+ return {
164
+ testsPass: testResult.passing > 0,
165
+ lintClean: lintResult.clean,
166
+ errors: [...testResult.errors, ...lintResult.errors]
167
+ };
168
+ } catch (error) {
169
+ return {
170
+ testsPass: false,
171
+ lintClean: false,
172
+ errors: [error.message]
173
+ };
174
+ }
175
+ }
176
+
177
+ async evaluateAgainstCriteria(criteria) {
178
+ // Parse criteria and check each
179
+ const criteriaLines = criteria.split('\n').filter(l => l.trim().startsWith('-'));
180
+ const results = {};
181
+
182
+ for (const criterion of criteriaLines) {
183
+ const key = criterion.replace('-', '').trim().substring(0, 20);
184
+ // Simulate checking (in reality would analyze code)
185
+ results[key] = Math.random() > 0.3; // 70% chance of meeting each criterion
186
+ }
187
+
188
+ const complete = Object.values(results).every(v => v === true);
189
+
190
+ return {
191
+ complete,
192
+ criteria: results,
193
+ unmet: Object.entries(results)
194
+ .filter(([_, v]) => !v)
195
+ .map(([k]) => k)
196
+ };
197
+ }
198
+
199
+ generateFeedback(evaluation) {
200
+ if (evaluation.unmet.length === 0) {
201
+ return 'All criteria met';
202
+ }
203
+
204
+ return `Still need to address:\n${evaluation.unmet.map(c => `- ${c}`).join('\n')}`;
205
+ }
206
+
207
+ async saveIterationArtifacts(iteration, artifacts) {
208
+ const iterDir = path.join(this.paths.history, `iteration-${String(iteration).padStart(3, '0')}`);
209
+ fs.mkdirSync(iterDir, { recursive: true });
210
+
211
+ fs.writeFileSync(
212
+ path.join(iterDir, 'artifacts.json'),
213
+ JSON.stringify(artifacts, null, 2)
214
+ );
215
+
216
+ // Log progress
217
+ const progress = {
218
+ iteration,
219
+ timestamp: Date.now(),
220
+ changes: artifacts.changes.length,
221
+ validation: artifacts.validation.testsPass,
222
+ errors: artifacts.validation.errors.length
223
+ };
224
+
225
+ fs.appendFileSync(this.paths.progress, JSON.stringify(progress) + '\n');
226
+ }
227
+
228
+ commitChanges(iteration, summary) {
229
+ try {
230
+ execSync('git add -A', { stdio: 'pipe' });
231
+ execSync(`git commit -m "Ralph iteration ${iteration}: ${summary}" --allow-empty`, { stdio: 'pipe' });
232
+ this.log(`Committed iteration ${iteration}`);
233
+ } catch (error) {
234
+ this.log(`Commit failed: ${error.message}`);
235
+ }
236
+ }
237
+
238
+ scanRelevantFiles() {
239
+ // Simulate file scanning
240
+ return ['index.js', 'auth.js', 'test.js'];
241
+ }
242
+
243
+ getTestStatus() {
244
+ try {
245
+ execSync('npm test', { stdio: 'pipe' });
246
+ return { passing: 5, failing: 0 };
247
+ } catch {
248
+ return { passing: 3, failing: 2 };
249
+ }
250
+ }
251
+
252
+ runTests() {
253
+ const status = this.getTestStatus();
254
+ return {
255
+ passing: status.passing,
256
+ failing: status.failing,
257
+ errors: status.failing > 0 ? ['Some tests failed'] : []
258
+ };
259
+ }
260
+
261
+ runLint() {
262
+ try {
263
+ execSync('npm run lint', { stdio: 'pipe' });
264
+ return { clean: true, errors: [] };
265
+ } catch {
266
+ return { clean: false, errors: ['Lint issues found'] };
267
+ }
268
+ }
269
+
270
+ getLastCommit() {
271
+ try {
272
+ return execSync('git log -1 --oneline', { encoding: 'utf8' }).trim();
273
+ } catch {
274
+ return 'No commits yet';
275
+ }
276
+ }
277
+
278
+ getCurrentIteration() {
279
+ try {
280
+ return parseInt(fs.readFileSync(this.paths.iteration, 'utf8'));
281
+ } catch {
282
+ return 0;
283
+ }
284
+ }
285
+
286
+ incrementIteration() {
287
+ const current = this.getCurrentIteration();
288
+ fs.writeFileSync(this.paths.iteration, String(current + 1));
289
+ }
290
+
291
+ getFeedback() {
292
+ try {
293
+ return fs.readFileSync(this.paths.feedback, 'utf8');
294
+ } catch {
295
+ return '';
296
+ }
297
+ }
298
+
299
+ isComplete() {
300
+ return fs.existsSync(this.paths.complete);
301
+ }
302
+
303
+ log(message) {
304
+ if (this.verbose) {
305
+ console.log(`[Ralph] ${message}`);
306
+ }
307
+ }
308
+
309
+ async run() {
310
+ while (!this.isComplete()) {
311
+ const iteration = this.getCurrentIteration();
312
+
313
+ if (iteration >= this.maxIterations) {
314
+ console.log('Max iterations reached!');
315
+ break;
316
+ }
317
+
318
+ // Worker phase
319
+ await this.runWorkerIteration();
320
+
321
+ // Reviewer phase
322
+ const review = await this.runReviewerIteration();
323
+
324
+ if (review.complete) {
325
+ console.log('Task completed!');
326
+ break;
327
+ }
328
+
329
+ // Brief pause between iterations
330
+ await new Promise(resolve => setTimeout(resolve, 1000));
331
+ }
332
+
333
+ // Final summary
334
+ this.printSummary();
335
+ }
336
+
337
+ printSummary() {
338
+ const iterations = this.getCurrentIteration();
339
+ const progress = fs.readFileSync(this.paths.progress, 'utf8')
340
+ .split('\n')
341
+ .filter(Boolean)
342
+ .map(line => JSON.parse(line));
343
+
344
+ console.log('\n=== Ralph Loop Summary ===');
345
+ console.log(`Total iterations: ${iterations}`);
346
+ console.log(`Total changes: ${progress.reduce((sum, p) => sum + p.changes, 0)}`);
347
+ console.log(`Final status: ${this.isComplete() ? 'COMPLETE' : 'INCOMPLETE'}`);
348
+ }
349
+ }
350
+
351
+ // CLI Interface
352
+ async function main() {
353
+ const args = process.argv.slice(2);
354
+ const command = args[0];
355
+
356
+ if (command === 'init') {
357
+ const task = args[1] || 'Implement a feature';
358
+ const criteria = args[2] || '- Tests pass\n- Code works\n- No errors';
359
+
360
+ const loop = new RalphLoop({ verbose: true });
361
+ await loop.initialize(task, criteria);
362
+ console.log('Ralph Loop initialized. Run with: node ralph-loop-implementation.js run');
363
+
364
+ } else if (command === 'run') {
365
+ const loop = new RalphLoop({ verbose: true });
366
+
367
+ if (!fs.existsSync(loop.paths.task)) {
368
+ console.error('No task found. Initialize first with: node ralph-loop-implementation.js init');
369
+ process.exit(1);
370
+ }
371
+
372
+ await loop.run();
373
+
374
+ } else if (command === 'status') {
375
+ const loop = new RalphLoop();
376
+ const iteration = loop.getCurrentIteration();
377
+ const complete = loop.isComplete();
378
+ const feedback = loop.getFeedback();
379
+
380
+ console.log(`Iteration: ${iteration}`);
381
+ console.log(`Status: ${complete ? 'COMPLETE' : 'IN PROGRESS'}`);
382
+ console.log(`Last feedback: ${feedback.substring(0, 100)}`);
383
+
384
+ } else {
385
+ console.log(`
386
+ Ralph Loop Implementation
387
+
388
+ Usage:
389
+ node ralph-loop-implementation.js init [task] [criteria] - Initialize a new loop
390
+ node ralph-loop-implementation.js run - Run the loop
391
+ node ralph-loop-implementation.js status - Check current status
392
+
393
+ Example:
394
+ node ralph-loop-implementation.js init "Add login feature" "- Tests pass\\n- JWT works\\n- Error handling"
395
+ node ralph-loop-implementation.js run
396
+ `);
397
+ }
398
+ }
399
+
400
+ if (import.meta.url === `file://${process.argv[1]}`) {
401
+ main().catch(console.error);
402
+ }
403
+
404
+ export { RalphLoop };