@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.
Files changed (2) hide show
  1. package/dist/index.js +22 -19
  2. 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
- function tryIncrementIteration(stateFilePath, lockFilePath, expectedIteration) {
49
- // Try to acquire lock by checking if lock file exists with different iteration
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
- const lockedIteration = parseInt(lockContent, 10);
53
- // If lock exists for same or higher iteration, someone else is handling it
54
- if (!isNaN(lockedIteration) && lockedIteration >= expectedIteration) {
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
- const nextIteration = expectedIteration + 1;
60
- writeFileSync(lockFilePath, String(nextIteration));
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 (parseInt(lockCheck, 10) !== nextIteration) {
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: Detected <promise>${state.completion_promise}</promise> - task complete!`);
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, don't continue
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 increment - this prevents race conditions
169
- const nextIteration = tryIncrementIteration(stateFilePath, lockFilePath, state.iteration);
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 statement is TRUE - do not lie to exit!)`
178
- : `Ralph iteration ${nextIteration} | No completion promise set - loop runs infinitely`;
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",
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",