@w32191/just-loop 0.1.0 → 0.1.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.
- package/dist/src/plugin/command-definitions.d.ts +6 -0
- package/dist/src/plugin/command-definitions.js +59 -0
- package/dist/src/plugin/config-handler.d.ts +1 -0
- package/dist/src/plugin/config-handler.js +10 -0
- package/dist/src/plugin/create-plugin.d.ts +12 -0
- package/dist/src/plugin/create-plugin.js +9 -2
- package/dist/src/plugin/tool-execute-before-handler.d.ts +18 -0
- package/dist/src/plugin/tool-execute-before-handler.js +23 -0
- package/package.json +6 -2
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const RALPH_LOOP_TEMPLATE = `You are starting a Ralph Loop - a self-referential development loop that runs until task completion.
|
|
2
|
+
|
|
3
|
+
## How Ralph Loop Works
|
|
4
|
+
|
|
5
|
+
1. You will work on the task continuously
|
|
6
|
+
2. When you believe the task is FULLY complete, output: \`<promise>{{COMPLETION_PROMISE}}</promise>\`
|
|
7
|
+
3. If you don't output the promise, the loop will automatically inject another prompt to continue
|
|
8
|
+
4. Maximum iterations: Configurable (default 100)
|
|
9
|
+
|
|
10
|
+
## Rules
|
|
11
|
+
|
|
12
|
+
- Focus on completing the task fully, not partially
|
|
13
|
+
- Don't output the completion promise until the task is truly done
|
|
14
|
+
- Each iteration should make meaningful progress toward the goal
|
|
15
|
+
- If stuck, try different approaches
|
|
16
|
+
- Use todos to track your progress
|
|
17
|
+
|
|
18
|
+
## Exit Conditions
|
|
19
|
+
|
|
20
|
+
1. **Completion**: Output your completion promise tag when fully complete
|
|
21
|
+
2. **Max Iterations**: Loop stops automatically at limit
|
|
22
|
+
3. **Cancel**: User runs \`/cancel-ralph\` command
|
|
23
|
+
|
|
24
|
+
## Your Task
|
|
25
|
+
|
|
26
|
+
Parse the arguments below and begin working on the task. The format is:
|
|
27
|
+
\`"task description" [--completion-promise=TEXT] [--max-iterations=N] [--strategy=reset|continue]\`
|
|
28
|
+
|
|
29
|
+
Default completion promise is "DONE" and default max iterations is 100.`;
|
|
30
|
+
const CANCEL_RALPH_TEMPLATE = `Cancel the currently active Ralph Loop.
|
|
31
|
+
|
|
32
|
+
This will:
|
|
33
|
+
1. Stop the loop from continuing
|
|
34
|
+
2. Clear the loop state file
|
|
35
|
+
3. Allow the session to end normally
|
|
36
|
+
|
|
37
|
+
Check if a loop is active and cancel it. Inform the user of the result.`;
|
|
38
|
+
export function getBuiltinCommands() {
|
|
39
|
+
return {
|
|
40
|
+
"ralph-loop": {
|
|
41
|
+
name: "ralph-loop",
|
|
42
|
+
description: "(builtin) Start self-referential development loop until completion",
|
|
43
|
+
template: `<command-instruction>
|
|
44
|
+
${RALPH_LOOP_TEMPLATE}
|
|
45
|
+
</command-instruction>
|
|
46
|
+
|
|
47
|
+
<user-task>
|
|
48
|
+
$ARGUMENTS
|
|
49
|
+
</user-task>`,
|
|
50
|
+
},
|
|
51
|
+
"cancel-ralph": {
|
|
52
|
+
name: "cancel-ralph",
|
|
53
|
+
description: "(builtin) Cancel active Ralph Loop",
|
|
54
|
+
template: `<command-instruction>
|
|
55
|
+
${CANCEL_RALPH_TEMPLATE}
|
|
56
|
+
</command-instruction>`,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function handleConfig(input: Record<string, unknown>): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getBuiltinCommands } from "./command-definitions.js";
|
|
2
|
+
export async function handleConfig(input) {
|
|
3
|
+
const existingCommands = input.command && typeof input.command === "object"
|
|
4
|
+
? input.command
|
|
5
|
+
: {};
|
|
6
|
+
input.command = {
|
|
7
|
+
...getBuiltinCommands(),
|
|
8
|
+
...existingCommands,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -25,9 +25,21 @@ type ChatMessageOutput = {
|
|
|
25
25
|
type EventInput = {
|
|
26
26
|
event?: unknown;
|
|
27
27
|
};
|
|
28
|
+
type ToolExecuteBeforeInput = {
|
|
29
|
+
tool?: unknown;
|
|
30
|
+
sessionID?: unknown;
|
|
31
|
+
callID?: unknown;
|
|
32
|
+
};
|
|
33
|
+
type ToolExecuteBeforeOutput = {
|
|
34
|
+
args?: {
|
|
35
|
+
name?: unknown;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
28
38
|
export type PluginHooks = {
|
|
29
39
|
"chat.message": (input: ChatMessageInput, output: ChatMessageOutput) => Promise<void>;
|
|
30
40
|
event: (input: EventInput) => Promise<void>;
|
|
41
|
+
config: (input: Record<string, unknown>) => Promise<void>;
|
|
42
|
+
"tool.execute.before": (input: ToolExecuteBeforeInput, output: ToolExecuteBeforeOutput) => Promise<void>;
|
|
31
43
|
};
|
|
32
44
|
export declare function createPlugin(ctx?: PluginInput, deps?: CreatePluginDeps): Promise<PluginHooks>;
|
|
33
45
|
export {};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createOpenCodeHostAdapter } from "../host-adapter/opencode-host-adapter.js";
|
|
2
2
|
import { createLoopCore } from "../ralph-loop/loop-core.js";
|
|
3
|
-
import {
|
|
3
|
+
import { handleConfig } from "./config-handler.js";
|
|
4
4
|
import { handleEvent } from "./event-handler.js";
|
|
5
|
+
import { handleToolExecuteBefore } from "./tool-execute-before-handler.js";
|
|
5
6
|
function extractSessionID(input) {
|
|
6
7
|
if (typeof input.sessionID === "string")
|
|
7
8
|
return input.sessionID;
|
|
@@ -37,16 +38,22 @@ export async function createPlugin(ctx, deps = {}) {
|
|
|
37
38
|
});
|
|
38
39
|
const core = createCore({ rootDir: ctx.directory, adapter });
|
|
39
40
|
return {
|
|
41
|
+
config: async (input) => {
|
|
42
|
+
await handleConfig(input);
|
|
43
|
+
},
|
|
40
44
|
"chat.message": async (input, output) => {
|
|
41
45
|
const sessionID = extractSessionID(input);
|
|
42
46
|
if (!sessionID)
|
|
43
47
|
return;
|
|
44
|
-
|
|
48
|
+
extractChatText(output.parts);
|
|
45
49
|
},
|
|
46
50
|
event: async (input) => {
|
|
47
51
|
if (!input.event)
|
|
48
52
|
return;
|
|
49
53
|
await handleEvent(input.event, core);
|
|
50
54
|
},
|
|
55
|
+
"tool.execute.before": async (input, output) => {
|
|
56
|
+
await handleToolExecuteBefore(input, output, core);
|
|
57
|
+
},
|
|
51
58
|
};
|
|
52
59
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type LoopCore = {
|
|
2
|
+
startLoop: (sessionID: string, prompt: string, options: {
|
|
3
|
+
maxIterations?: number;
|
|
4
|
+
completionPromise?: string;
|
|
5
|
+
}) => Promise<unknown>;
|
|
6
|
+
cancelLoop: (sessionID: string) => Promise<unknown>;
|
|
7
|
+
};
|
|
8
|
+
type ToolExecuteBeforeInput = {
|
|
9
|
+
tool?: unknown;
|
|
10
|
+
sessionID?: unknown;
|
|
11
|
+
};
|
|
12
|
+
type ToolExecuteBeforeOutput = {
|
|
13
|
+
args?: {
|
|
14
|
+
name?: unknown;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export declare function handleToolExecuteBefore(input: ToolExecuteBeforeInput, output: ToolExecuteBeforeOutput, core: LoopCore): Promise<void>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { parseRalphLoopCommand } from "../commands/parse-ralph-loop-command.js";
|
|
2
|
+
function normalizeCommandName(name) {
|
|
3
|
+
return name.startsWith("/") ? name : `/${name}`;
|
|
4
|
+
}
|
|
5
|
+
export async function handleToolExecuteBefore(input, output, core) {
|
|
6
|
+
if (input.tool !== "skill")
|
|
7
|
+
return;
|
|
8
|
+
if (typeof input.sessionID !== "string")
|
|
9
|
+
return;
|
|
10
|
+
if (typeof output.args?.name !== "string")
|
|
11
|
+
return;
|
|
12
|
+
const command = parseRalphLoopCommand(normalizeCommandName(output.args.name));
|
|
13
|
+
if (!command)
|
|
14
|
+
return;
|
|
15
|
+
if (command.kind === "cancel") {
|
|
16
|
+
await core.cancelLoop(input.sessionID);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
await core.startLoop(input.sessionID, command.prompt, {
|
|
20
|
+
maxIterations: command.maxIterations,
|
|
21
|
+
completionPromise: command.completionPromise,
|
|
22
|
+
});
|
|
23
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@w32191/just-loop",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"description": "OpenCode plugin package for just-loop.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "./dist/src/index.js",
|
|
@@ -12,7 +12,11 @@
|
|
|
12
12
|
"import": "./dist/src/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
-
"files": [
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
16
20
|
"publishConfig": {
|
|
17
21
|
"access": "public"
|
|
18
22
|
},
|