@sureshsankaran/ralph-wiggum 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +22 -19
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -45,22 +45,26 @@ function extractPromiseText(text) {
|
|
|
45
45
|
return match ? match[1].trim().replace(/\s+/g, " ") : null;
|
|
46
46
|
}
|
|
47
47
|
// Atomically increment iteration using file-based locking
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
// Returns the next iteration number if we won the lock, null if another handler is processing
|
|
49
|
+
function tryClaimIteration(stateFilePath, lockFilePath, currentIteration) {
|
|
50
|
+
const nextIteration = currentIteration + 1;
|
|
51
|
+
// Check if lock exists for THIS specific iteration transition
|
|
50
52
|
if (existsSync(lockFilePath)) {
|
|
51
53
|
const lockContent = readFileSync(lockFilePath, "utf-8").trim();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
// Lock format: "from:to" e.g., "1:2" means transitioning from iteration 1 to 2
|
|
55
|
+
const [fromStr, toStr] = lockContent.split(":");
|
|
56
|
+
const from = parseInt(fromStr, 10);
|
|
57
|
+
const to = parseInt(toStr, 10);
|
|
58
|
+
// If lock exists for this exact transition, someone else is handling it
|
|
59
|
+
if (from === currentIteration && to === nextIteration) {
|
|
55
60
|
return null;
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
|
-
// Write our lock
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// Double-check we got the lock (simple mutex)
|
|
63
|
+
// Write our lock with format "from:to"
|
|
64
|
+
writeFileSync(lockFilePath, `${currentIteration}:${nextIteration}`);
|
|
65
|
+
// Double-check we got the lock
|
|
62
66
|
const lockCheck = readFileSync(lockFilePath, "utf-8").trim();
|
|
63
|
-
if (
|
|
67
|
+
if (lockCheck !== `${currentIteration}:${nextIteration}`) {
|
|
64
68
|
return null; // Someone else won the race
|
|
65
69
|
}
|
|
66
70
|
// Update state file
|
|
@@ -105,7 +109,7 @@ export const RalphWiggumPlugin = async ({ client, directory }) => {
|
|
|
105
109
|
const promiseText = extractPromiseText(part.text);
|
|
106
110
|
if (promiseText === state.completion_promise) {
|
|
107
111
|
completionDetected = true;
|
|
108
|
-
console.log(`\nRalph loop
|
|
112
|
+
console.log(`\nRalph loop complete! Detected <promise>${state.completion_promise}</promise>`);
|
|
109
113
|
try {
|
|
110
114
|
unlinkSync(stateFilePath);
|
|
111
115
|
}
|
|
@@ -125,9 +129,8 @@ export const RalphWiggumPlugin = async ({ client, directory }) => {
|
|
|
125
129
|
const isIdle = event.type === "session.status" && event.properties?.status?.type === "idle";
|
|
126
130
|
if (!isIdle)
|
|
127
131
|
return;
|
|
128
|
-
// If completion was already detected,
|
|
132
|
+
// If completion was already detected, silently ignore
|
|
129
133
|
if (completionDetected) {
|
|
130
|
-
console.log("\nRalph loop: Completion already detected, not continuing");
|
|
131
134
|
return;
|
|
132
135
|
}
|
|
133
136
|
const sessionID = event.properties?.sessionID;
|
|
@@ -165,17 +168,17 @@ export const RalphWiggumPlugin = async ({ client, directory }) => {
|
|
|
165
168
|
catch { }
|
|
166
169
|
return;
|
|
167
170
|
}
|
|
168
|
-
// Try to atomically
|
|
169
|
-
const nextIteration =
|
|
171
|
+
// Try to atomically claim this iteration - this prevents race conditions
|
|
172
|
+
const nextIteration = tryClaimIteration(stateFilePath, lockFilePath, state.iteration);
|
|
170
173
|
if (nextIteration === null) {
|
|
171
|
-
// Another event handler won the race, skip this one
|
|
174
|
+
// Another event handler won the race, skip this one silently
|
|
172
175
|
return;
|
|
173
176
|
}
|
|
174
|
-
console.log(`\nRalph loop: Starting iteration ${nextIteration}`);
|
|
175
177
|
// Build system message
|
|
176
178
|
const systemMsg = state.completion_promise
|
|
177
|
-
? `Ralph iteration ${nextIteration} | To stop: output <promise>${state.completion_promise}</promise> (ONLY when
|
|
178
|
-
: `Ralph iteration ${nextIteration} | No completion promise set
|
|
179
|
+
? `Ralph iteration ${nextIteration} | To stop: output <promise>${state.completion_promise}</promise> (ONLY when TRUE)`
|
|
180
|
+
: `Ralph iteration ${nextIteration} | No completion promise set`;
|
|
181
|
+
console.log(`\n${systemMsg}`);
|
|
179
182
|
// Send the same prompt back to continue the session
|
|
180
183
|
try {
|
|
181
184
|
if (sessionID) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sureshsankaran/ralph-wiggum",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Ralph Wiggum iterative AI development plugin for OpenCode - continuously loops the same prompt until task completion",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|